Crystal Reports - Accessing default value for a parameter using .NET SDK

We have been using Crystal Reports for our Travel CRM with good results for a few years now. We use a completely custom ExtJs based experience for Report viewing which includes a custom user interface for entering report parameters (see screenshot below for an example) and a custom toolbar for managing report navigation and exporting etc (I had blogged about the toolbar earlier here).

A custom User Interface for entering report parameters for Crystal Reports

 

Everything worked good. However the client recently came back to us mentioning that our interface does not populate the default value for a report parameter automatically. Well we never supported it earlier, so we began looking for a way to extract the default value for a parameter using the Crystal Reports developer version for Visual Studio SDK to be able to populate the same in our interface. It took us sometime to figure out the way to accomplish this using the SDK, so I thought I would share it for everyone's benefit.

To start with, let's clear out some Crystal Report SDK's nomenclature which is a bit misleading in my opinion. Crystal Report parameters have something known as default values in the SDK. This is not exactly the default value for a parameter, rather a list of options from which you can choose a value (i.e. pre-defined values for a parameter available for selection). For example, in the screenshot below, you are defining available values for the "Detail or Summary" parameter. When executing the report, these values be available in the drop-down as you can see in the screenshot.

Parameter Default values in Crystal Reports are actually pre-defined values available for selection

 

Not exactly intuitive you would agree.

Next we come to another option on the parameter which is labeled as "Default value" for the parameter in the Report Designer's user interface (again reference the screenshot below).

Default value for a Crystal Report Parameter

 

This is what most people would take as the default value for a parameter in my understanding. The Crystal Reports SDK calls this as "Initial Value" of the parameter; pretty interesting, ain't it...


With the background out of our way, let's now come to the code to extract these values from a CR report template using the SDK. I will demonstrate extracting both default as well as initial values of a parameter.

Both these types of values can be extracted from a CrystalDecisions.CrystalReports.Engine.ReportDocument object. Given a path to CR report's template (.rpt) file, here's how you load it into a ReportDocument object:

 

ReportDocument doc = new ReportDocument();
doc.Load(reportFilePath);

 

Next we use the ReportDocument object to extract the default values for each parameter (remember default values are the list of pre-defined values as discussed above).

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }foreach (ParameterFieldDefinition p in doc.DataDefinition.ParameterFields) { if (p.ParameterFieldUsage != ParameterFieldUsage.NotInUse) { reportParams.Add(p.Name, new { type = p.ParameterValueKind, label = p.PromptText, required = (!p.EnableNullValue) || (!p.IsOptionalPrompt), allowCustom = p.EnableAllowEditingDefaultValue, allowMultiple = p.EnableAllowMultipleValue, rangeType = p.DiscreteOrRangeKind, defaultValues = p.DefaultValues, initialValues = new { discreetValues = new List<object>() } }); } }{/syntaxhighlighter}

 

We iterate over ReportDocument.DataDefinition.ParameterFields collection. For each parameter, we check if its in use on the report and if yes, extract various configuration options for the parameter including its default values (p.DefaultValues). The above code extract is from our Travel CRM, you can off-course adapt it anyway you need to.


Finally, we extract the InitialValues for each parameter (which you would recall is labeled as default value of the parameter in the Report Designer UI). Again, for some reason, the SDK developers chose to expose the InitialValues using a completely different set of objects (rather than the ParameterFieldDefinition).

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }foreach (CrystalDecisions.ReportAppServer.DataDefModel.ISCRParameterField clientParameterFieldDefinition in doc.ReportClientDocument.DataDefController.DataDefinition.ParameterFields) { foreach (var initialValue in clientParameterFieldDefinition.InitialValues) { var discreetInitialValue = initialValue as CrystalDecisions.ReportAppServer.DataDefModel.ParameterFieldDiscreteValue; if (discreetInitialValue != null) { var initialValue = discreetInitialValue.Value; //Use initial value anyway you would like to. In our case, we stored it and passed to our ExtJs UI to populate in the interface. } } }{/syntaxhighlighter}

 

You need to goto ReportDocument.ReportClientDocument.DataDefController.DataDefinition.ParameterFields and check the InitialValues collection for each field. Then you ensure each item of the InitialValues collection is of type ParameterFieldDiscreteValue, and if it is, that's your default value for that parameter. It appears the SDK developers chose to keep InitialValues multi-valued so report designers can input multiple default values (aka initial values) for mulit-valued report parameters.

Please note the last part (extracting InitialValues for a parameter) is written using 13.0.10.1385 version of the SDK. I believe there's a minor variation to it if you use an earlier version (I don't have the earlier version, so can't tell the difference exactly but you can use intelli-sense or Reflector to find the exact property hierarchy).

If its different for your SDK version and you aren't able to figure it out, feel free to use the comment form below for seeking help (clearly mention your full SDK version in this case) and I would try to solve the puzzle for you.

 

Web 2.0: 

Comments

Could you please share all the required dlls and other necessary code files to successfully execute the above explained code.

rahul's picture

Hi Chandra, you are asking for too much. Obviously we can't share our production code and I usually run short on time for creating test projects for demonstration. I think you can just add reference to CrystalDecisions .Net dlls, import namespaces and start using the code. This page lists the downloads links for Crystal Reports Developer version for Visual Studio:
http://scn.sap.com/docs/DOC-7824 

Great article! It helps a lot. However our case is a bit more complex. We have the default value set for a parameter in the sub-report. I tried to get the .ReportClientDocument.DataDefController.DataDefinition.ParameterFieldson the sub-report level. It threw me a Sub-Report Not Supported exception. (This happens quite a lot even for some other methods!). Is there a way to set the default value to a parameter in sub-report?

rahul's picture

Hi Jack,

I haven't tested it, but try along following lines:

Sections crSections = mainReportDocument.ReportDefinition.Sections;
//loop through all the sections to find all the report objects
foreach (Section crSection in crSections)
{
	ReportObjects crReportObjects = crSection.ReportObjects;
	//loop through all the report objects to find all the subreports
	foreach (ReportObject crReportObject in crReportObjects)
	{
		if (crReportObject.Kind == ReportObjectKind.SubreportObject)
		{
			//you will need to typecast the reportobject to a subreport object once you find it
			SubreportObject crSubreportObject = (SubreportObject) crReportObject;
			//open the subreport object
			var subReport = crSubreportObject.OpenSubreport(crSubreportObject.SubreportName);
			subReport.SetParameterValue("MyParam", value);
		}
	}
}