[Download Sample App] | [Part III]
In Part I of this article, we introduced a sample application that allows developers to display reports. This application allows users to select a Crystal Report to display. The application will prompt for any parameters that the report has, apply the user's entries, and display the report.
In this article, I will go through the class that actually creates the parameters from the report. There is a class called PCRMControls which includes extensions of standard server controls. These extended controls are used in populating the web page to capture the parameter information from the user.
The class PCRMCreateCRObjects is written in VB .NET and utilizes a DLL called Fesersoft.VB.Comments. This is a free comments component which allows VB .NET to create XML comments. This class is included in the web project as a .vb file. I would probably separate this into another project as I refactor the application, following a better separation of the business logic from the GUI. Otherwise, the project utilizes standard Crystal and .NET libraries. Now on to the object!
Building Those Parameters!
The class PCRMCreateCRObjects contains two methods, GetBuilder and IsThisAValidCrystalFile. GetBuilder uses some of the extended controls from the class PCRMControls to add to the controls collection (controlsCollection). The web page populates the form with the controls in controlsCollection.
GetBuilder takes the parameter loadReportName, which is the path and report name. GetBuilder then uses IsThisAValidCrystalFile to check if the passed report name is a true Crystal Report. IsThisAValidCrystalFile makes sure that the file is a valid file and that the Crystal Report object can load the file.
To determine if this is a valid Crystal file, IsThisAValidCrystalFile relies on loading the report into a Crystal ReportDocument. First, I validate the existence of the file, using the System.IO namespace. Using the Exists method of System.IO.File class, I check if that returns true. If it does, then I create a new ReportDocument object and attempt to load the file. This all happens within a try-catch block. Assuming this falls through the try block, a true is passed back to the calling method. If an error is encountered, or if the file does not exist, a false is passed back.
Dim myFile As IO.File
Dim fileExists As Boolean = False
Try
If myFile.Exists(fileNameToCheck) Then
Dim oTryCrystal As New CrystalDecisions.CrystalReports.Engine.ReportDocument()
oTryCrystal.Load(fileNameToCheck)
oTryCrystal.Close()
fileExists = True
End If
Catch e As Exception
fileExists = False
End Try
myFile = Nothing
Return fileExists
If this is not a valid Crystal Report, then controlsCollection stays empty. If this is a valid report name, the report object loads the report. The report Title is retrieved using the report title property, SummaryInfoReportTitle. Then the method begins a loop to add controls based on the parameters to the collection.
If IsThisAValidCrystalFile(loadReportName) Then
oReport.Load(loadReportName)
crTitle = oReport.SummaryInfo.ReportTitle
Dim oTable As CrystalDecisions.CrystalReports.Engine.Table
Dim oCRParam As CrystalDecisions.CrystalReports.Engine.ParameterFieldDefinition
' Loop through the tables contained in the report.
For Each oTable In oReport.Database.Tables
' Loop through the parameters in the fields
For Each oCRParam In oReport.DataDefinition.ParameterFields
Next we loop through the database tables in the report, using the Crystal ReportDocument object collection Database.Tables. Within that loop, I loop through the Parameter field collection in DataDefinition.ParameterFields. This ensures that if there are multiple tables within the report, all parameters for that table are discovered.
Next, within that parameter field loop, the parameter field type is evaluated by a case statement. Once the data type is determined, the correct web form object is put into the collection. The case statement is a bit long with different data types; it still does not have all the data types covered. This would be a great place to extend the application.
Each case statement is similar in content. I add the appropriate extended server control. That object is a slightly modified standard ASP.NET web server control. That server control is assigned a LabelID that refers to a descriptive label control. In your web page, use this LabelID to match this control to a label that gives a user friendly prompt for this parameter. Then the object will be added to the controls collection.
For instance, a boolean parameter is assigned to a checkbox. The control PCRMChkObject is instantiated in this case. PCRMChkObject has a method that returns a modified checkbox that includes a label ID. To add the object to the controls collection, the Get method of the objects class is called. In this case, that is GetCheck. This method sets the NamingContainer.ID, the Text property of the control and the CSSClass for the control. This method utilizes the Parameter object. All of the Get methods are similar for each control.
Select Case oCRParam.ParameterValueKind
Case CrystalDecisions.[Shared].ParameterValueKind.BooleanParameter
Dim newCheck As New PCRMChkObject
newCheck.LabelID = labelName
controlsCollection.Add(newCheck.GetCheck(oCRParam), "control"
& Trim(CStr(controlNum)))
newCheck = Nothing
Case CrystalDecisions.[Shared].ParameterValueKind.CurrencyParameter
Dim newText As New PCRMTextBoxObject
newtext.currLabelID = labelName
controlsCollection.Add(newText.GetTextBox(oCRParam), "control"
&</font><font face="Verdana" size="2"> Trim(CStr(controlNum)))
newText = Nothing
Other instances include a textbox for most types and a calendar for date-time parameters. These controls are modified in similar ways, with a Get function and a LabelID property.
After the case statement, a label server control is created for the control just created. The label's text is set using the PromptText property in the object. I am assuming the report creator actually populates the prompt text for parameters at the report level.
I set label controls currLabelID to the labelname variable. This is the same name that the Parameter control's LabelID property is set to, which allows the calling program to match up the Parameter input control to the Parameter label.
End Select
Dim newLabel As New PCRMLabelObject
newLabel.currLabelID = labelName
controlsCollection.Add(newLabel.GetLabel(oCRParam), labelName)
controlNum = controlNum + 1</font>
To keep the ID unique for the web page, a variable controlnum is incremented through each loop. At the end of the method, we close the report.
In Summary
This part of the walkthrough shows you how I actually determine parameter types and display them. To accomplish this we use customized standard ASP.NET server controls and a control collection that’s part of a custom object. The method GetBuilder from the PCRMCreateCRObjects class is the heavy lifter here.
In the end, your calling ASP.NET page receives a collection of parameter controls, and labels for those controls, based on the passed report. This is what allows the dynamic generation of parameter input form objects. To review the first part of this article, refer to Part I. Also, for answers to other Crystal-related questions, don’t forget ASPAlliance's resource for Crystal: Crystal Alliance. In a future article, I'll cover what it takes to display a Crystal report!