RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


The Baker's Dozen: 13 Productivity Tips for Crystal Reports Redux : Page 2

This article is a redux, or "Version 2.0" of the Baker's Dozen article on Crystal Reports that ran in the January/February 2005 issue of CoDe Magazine. The article updates some of the classes, covers some new features in Crystal Reports XI, and demonstrates techniques to help developers get the most out of Crystal Reports.

Tip 1: Report Parameters
I want to add a single Boolean flag for my existing report to determine whether to print or suppress a specific section. My report uses a strongly typed dataset as the design-time data source, but I don't want to add a column to the dataset just for one single flag. Instead, I'd like to add a simple parameter to my report, and then programmatically set the value at run time.

I can implement and use report parameter fields by doing the following:

  1. In the Crystal Reports Field Explorer, right-click the "Parameter Fields" list selection, and then select the option for New (see Figure 1).
  2. Crystal Reports displays the "Create Parameter Field" screen (see Figure 2), where I can enter the name of the parameter. Since this parameter indicates whether the report displays detail data, I'll call the parameter ShowDetails. Make sure to set the value type to Boolean.
  3. After I save the entries, Crystal Reports displays the parameter field (see Figure 3).
Figure 1: Adding a parameter to a report.
Figure 2: Defining the report parameter.
Figure 3: Parameter is now displayed in Field Explorer.
Now that I've added the parameter field, I can use it to conditionally suppress the details section (or any other section) when ShowDetails is set to false by doing the following:

Figure 4: Using the parameter in a formula.
  1. Launch the Section Expert.
  2. Select the Details section in the list of available sections.
  3. Select the check box on the right-hand side for Suppress, and then click the formula icon to the right of the check box.
  4. In the formula editor for the Suppress option (see Figure 4), enter the following formula expression: not {?ShowDetails}. Yes, the formula is the reverse of the Boolean flag—an alternative is to change the flag to something like SuppressDetails and handle it accordingly.
Finally, to set the value at run time, create an instance of the report, and then use the report method SetParameterValue:

Annotating reports is like paying insurance premiums: you do it because of the one percent change that it will come in handy someday. How specifically you annotate falls under standards-the fact that you annotate falls under practices.
   bool lShow = true;
   oReport.SetParameterValue("ShowDetails", lShow);
Tip 2: Generic Header/Footer and Startup Template
Just like my application screens, I want my reports to have a common appearance and format. Therefore, I want to build a base report template that I can use for all of my reports.

In the original article, I stressed consistency and meaningful annotations in building reports. I left it as an exercise for the reader to build a reusable template with a common header and footer structure. I received some e-mail feedback that some starter examples would have gone a long way.

Figure 5: Basic report with generic header and footer.
My goal is Figure 5, with a report header that shows company information, date/time printed, the report name and any subtitle information, and the ubiquitous "Page X of Y". The header contains the name of the user who generated the report, the version of the software, user footnotes, and the data source used for the report. These annotations can prove valuable any time I look at a generated copy afterwards and need to know who generated the report, when, and the database/software version used at the time.

Annotating reports is like paying insurance premiums: you do it because of the one percent chance that it will come in handy some day. How specifically you annotate falls under standards—the fact that you annotate falls under practices.

Building a base template report like the one in Figure 5 involves four steps.

First, I need to build a dataset (dsReportInfo) containing the data elements that I want to annotate. I'll provide an interface to populate these later in Tip 3. For right now, I'll identify the elements, as shown in Table 3.

Second, I need to construct the header and footer sections, which I'll build as separate report files. Figure 6 and Figure 7 show rptHeader.RPT and rptFooter.RPT. Both reports use dsReportInfo as the design-time data source, with fields dragged from the Crystal Reports Field Explorer onto the design area. Note that the header report in Figure 6 contains some parameter and formula expressions for page number, page count, and the page X of Y annotation. I'll explain this in a few paragraphs.

Figure 6: Basic generic header.
Figure 7: Basic generic footer.
Figure 8: Basic base report template.
Third, I'll build a base template report (rptBase.RPT) that incorporates rptHeader.RPT and rptFooter.RPT as subreports (see Figure 8). I can do this by creating a new report and inserting the two subreports as follows:

  1. Right-click in the report body and select Insert…Subreport.
  2. Crystal Reports will show the Insert Subreport screen. Navigate either using the pull-down list or the Open File dialog box to select rptHeader.RPT.
  3. Place the subreport for the header in the page header section of the main report.
  4. Repeat this process for rptFooter.RPT, and then place it in the page footer section of the main report.
  5. Very important: anytime I change the header or footer subreport, I want the parent base report to automatically reflect those changes. So right-click each subreport, choose Format Object, and then go to the Subreport tab. Select the check box for the option Re-import When Opening.
Crystal Reports, like any other report writer, is a presentation vehicle for your data. So to repeat what was I two years ago, building good reports is all about three things: data, data, and data.
Now, there's one more thing to make the base template complete. I purposely did not place the standard Crystal Reports special field "Page X of Y" (or Page N of M, as Crystal Reports calls it) in rptHeader.RPT. If I look closely at the upper-right corner of Figure 6, I'll instead see a custom Crystal Reports formula called @PageXofY. So what gives?

To explain, suppose I had simply placed the standard Crystal Reports Page N of M field in the subreport, inserted the subreport into a base template report, and then used the base for any report that generated more than one page. The subreport would ALWAYS show "PAGE 1 OF 1" on every page. The reason is simple—every time the subreport fires for each page heading in the parent report, it is starting over with a page number and page count of 1. In this situation, the subreport has no knowledge of page information in the parent report.

So I need to instruct the parent-base report to tell rptHeader.RPT the current page number and page count from the parent report. Fortunately, I can leverage parameter fields from Tip 1, and then pass the page number and page count as a subreport link from rptBase.RPT to rptHeader.RPT. Follow these steps:

Figure 9: Subreports link page: to pass parameters from a parent report to a subreport.
  1. In rptHeader.RPT, create two parameter fields called PageNumber and TotalPageCount.
  2. In the same report, create a formula field called PageXofY, using the code listed after step 4.
  3. In rptBase.RPT, create two new formula fields called PageNumber and TotalPageCount. The formula expressions are nothing more than the Crystal Reports special field variables with the same names. (I need to pass these values as a subreport link—unfortunately, Crystal Reports does not allow me to pass a system variable directly as a subreport link. The way around this is to create a formula based solely on the variable, and then pass the formula to the subreport.)
  4. Right-click the header subreport and select the option Change Subreport Links. In the Subreports Link screen (see Figure 9), map the formula for the page number to the corresponding page number parameter in the header subreport. Then repeat the process for the page count.
   'Page ' + Trim(ToText({?PageNumber},0)) +
    ' of ' +  Trim(ToText({?TotalPageCount},0))
This may seem like a large number of steps, but just like building any component, I only have to go through these steps once.

Finally, I can use rptBase.RPT as the basis for all future reports. When I create a new report, Crystal Reports prompts me to create a new report using the report wizard—as a blank report or from an existing report. By selecting this second option, and then selecting rptBase.RPT, I can build reports using the base report as the template.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date