Virtual Developer Workshop: Containerized Development with Docker
This parameter's screen was generated dynamically just by reading the .rpt file!
The company I own provides custom software solutions to Fortune 500 companies in Los Angeles, CA and Miami, FL for C# and VB .NET Winform and WebForm applications. We can provide a Web or Winform app that would take six programmers a year to complete in just days, thereby saving our clients, in some cases, millions of dollars.
To be able to do do this, I have written what I call "Model Applications" of MDI & SDI WinForms, Web Apps, and so forth that simply require changing the artwork and business logic.
I use Crystal Reports in my model apps for creating reports. This is the first part of a two-part article that will demonstrate how to implement a generic solution to using Crsytal Reports in Winforms and Web Apps.
This part will deal with Winforms. Part II will deal with Web Apps.
Crystal Reports is not easy to work with, and my experience has found that it has plenty of bugs and quirks. But, the big companies all seem to like it, so I had to develop a generic approach to using it.
One of the worst features of Crystal Reports is the way it handles report Parameters by presenting each parameter in a separate screen; clients really hate this! To solve this, this demo will show you how to present ALL of the parameters contained in a .rpt file in a SINGLE screen to the user.
This demo displays reports using two screens, a Reports Viewer and a Parameters Viewer. You could combine these screens; this is easy to do. These screens contain the following features:
- Reports Viewer. This screen has a ComboBox that displays a list of reports that the user can select from. When the user presses the "Get Report" button, a modal window, called the Parameters Viewer, will be launched.
- Parameters Viewer. This screen displays the parameters contained in the report selected in a datagrid that you dynamically add controls to to make selecting parameter values easier for the user. After setting the parameter values for the selected report, the user will close the Parameters Viewer and the Reports Viewer will display the selected report with the selected parameters.
Crystal Reports creates a binary file with an ".rpt" extension that contains ALL of the information you need to display any report. That is what you will use in this generic solution.
- Select the .rpt file
- Read the parameter information directly from the .rpt file
- Build a table dynamically that displays all of the parameters in the selected .rpt report file.
- The parameter table that you create dynamically also must contain controls that also are created dynamically to facilitate the user's selection of parameters, such as a date calendar, checkboxes, and so forth.
- You must create validation controls dynamically from the parameter data that you read from the .rpt file.
- Finally, you pass the parameter data into the Crystal Viewer and display your selected Crystal Report.
- Database connection information is read dynamically from the selected .rpt file.
In the demo reports included, I didn't bother to connect to any data source because doing that is trival and the main point of this article is to show how to display the parameter data in a datagrid with selection controls dynamically. But, all of the code that does this is in place in the demo and will read the database information dynamically if there is any database information in the .rpt file.
Reading Parameter Data from .rpt Report Files
You started by pre-defining the columns of your Datagrid of Parameters as follows: Parameter, Kind, Value, Min, Max, and Prompt. You will add each parameter kind as a new row to your datagrid.
To dynamically build a datagrid of parameters, you read parameters from the .rpt file as follows:
// Get parameter field definitions in collection of // ParameterFieldDefinition objects CrystalDecisions.CrystalReports.Engine.ParameterFieldDefinitions crParamFieldDefinitions = crDoc.DataDefinition.ParameterFields; // Iterate over collection, processing each ParameterFieldDefinition foreach (CrystalDecisions.CrystalReports.Engine.ParameterFieldDefinition def in crParamFieldDefinitions)
For each parameter in the foreach loop, you add a row to your dynamic datagrid that has pre-defined columns.
Dynamically Adding Controls to Your Datagrid of Parameters
What is unusual about your datagrid of parameters is that you are adding each parameter as a new row instead of as a new column, which is what is more commonly done in datagrids. This means that I needed to implement a different approach to adding user controls. To accomplish this, I used the "GotFocus" event of the datagrid to selectively add/remove controls based upon the Parameter Kind listed in Column 2 of the datagrid.
For the puposes of this article, I implemented only three control types: DateTime, TimePicker, and CheckBox.
For example, when a user clicks on the datagrid, if Column 2 has a value of "DateTime," a DateTime Control will appear in the data cell for the user to select a "DateTime." I should point out that some programmers prefer using a "Radio Button" for Boolean values, but I prefer using a simple CheckBox for Boolean values that I implemented in the demo here. It should be obvious that you can implement any controls that turn you on or that a client requests.
The DateTime Picker Control
The DateTime Picker is a control that allows the user to select either a date, a datetime, or a time value. It provides two distinct GUI interfaces for a Calendar and a Time Spinner.
|h||12-hour - Hour with one digit if value is less than 10|
|hh||12-hour - Hour with a leading 0 if the value is less than 10|
|H||24-hour - Hour with one digit if the value is less than 10|
|HH||24-hour - Hour with a leading 0 if the value is less than 10|
|m||Minute - Minute with one digit if the value is less than 10|
|mm||Minute - Minute with a leading 0 if the value is less than 10|
|t||AM/PM - Letter A or P for the AM or PM section|
|tt||AM/PM - Letters AM or PM for the last section|
To set the DateTime control as a Time Spinner, set the ShowUpDown Boolean property to "true," and change the Format property to a Time value. The Time Picker control is a spin button made of different sections: the hours value, the minutes value, the optional seconds value, and the optional AM/PM string. To change the time, the user clicks a section and uses either the mouse or the keyboard to increase or decrease that particular value. To change another value, the user must first click it and then use the spin button.
By default, the time displays using the H:M:SS AM/PM format. This means that the time uses 1 digit for the hours from 0 to 9, 1 digit for the minutes from 0 to 9, 1 digit for the seconds from 0 to 9, and AM or PM for morning or afternoon. To customize the way the time displays, first set the Format property to Custom. Then, in the CustomFormat property, use a combination of the following characters to create a custom format: hh:mm:tt
I set the format at run time by assigning the desired format to the DateTimePicker::CustomFormat property. By default, the control assumes the time of the computer when the control was added. If you want to set a different time, apply a Format combination to the Value property. In the same way, at any time, you can retrieve the time value on the control by accessing the Value property.