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 6

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 11: Using Crystal Reports in ASP.NET 2.0 Web Forms
ASP.NET 2.0 includes an enhanced ReportViewer and CrystalReportSource control, as well as a new CrystalReportsPartViewer control. The latter allows me to work with ASP.NET 2.0 Web Parts, which let me work with individual sections of a page. The enhanced ReportViewer allows users to preview and navigate through a report using a preview toolbar similar to that found in the Crystal Reports Windows Forms toolbar. A future Baker's Dozen article will cover ASP.NET 2.0 data-driven Web applications and Web reporting.

Tip 12: Generating Reports against Custom .NET Classes Instead of Datasets
I prefer to work with data in custom classes and custom collections, as opposed to datasets. I'd like to generate a report directly against those objects, without having to use datasets.

In both the original article and this article, I've focused on datasets as the design-time and run-time source for the push model. However, I can also push .NET custom collections into a report.

The following code shows a basic class with two simple properties for name and salary called TestReportInfo.

   using System;
   using System.Collections.Generic;
   using System.Text;
   namespace ReportWithClassTest
      public class TestReportInfo
         public TestReportInfo(string cEmpName, decimal nSalary)
            this.EmpName = cEmpName;
            this.Salary = nSalary;
         private string _EmpName;
         public string EmpName
            get { return _EmpName; }
            set { _EmpName = value; }
         private decimal _Salary;
         public decimal Salary
            get { return _Salary; }
            set { _Salary = value; }
I can use the preceding class as the design-time data source for a test report, by doing the following:

  1. Launch Crystal Reports and open the Database Expert (as shown in Figure 19).
  2. Click Project Data, and then click .NET Objects.
  3. Select the class containing the objects that the report will use.
  4. Drag the objects from the Crystal Reports Field Explorer onto the report body as needed (as shown in Figure 20).
Figure 19: Selecting a .NET object.
Figure 20: Properties from .NET class available in Field Explorer.
That covers the design-time aspect—what about pushing a collection of objects into the report at run time? It's just as easy. Here's the code to create a List object (using the new .NET 2.0 Generics namespace) to store multiple instances of the TestReportInfo class.

   List<TestReportInfo> oList = new List<TestReportInfo>();
   oList.Add(new TestReportInfo("Kevin Goff",90000));
   oList.Add(new TestReportInfo("John Goff",95000));
   oList.Add(new TestReportInfo("Mike Smith",99000));
   CrystalReport1 oRpt = new CrystalReport1();
Then I can instantiate the report object and use the report's SetDataSource method to push the List object into the report.

So I can push a DataSet, DataTable, DataReader, or (in this instance) anything that implements System.Collections.IEnumerable into a Crystal Reports report.

Additionally, if I'm using Crystal Reports XI, I can now pass a DataView object. Prior versions of Crystal Reports did not support the DataView object. So if I'm using anything prior to Crystal Reports XI and want to push the contents of a DataView into a report, I have two choices:

If I'm using Visual Studio 2005, I can use the new ADO.NET method, DataView.ToTable, to convert the view to a table.

If I'm using Visual Studio 2003, I can use the following code to create a DataTable from a DataView:

   public DataTable ViewToTable(DataView dv)
   // Create a new table structure from the 
   // table object of the view, and then loop 
   // through the view and import the rows into 
   // the new table
        DataTable DtReturn = dv.Table.Clone();
   foreach (DataRowView drv in dv)
   return DtReturn;
Tip 13: A Potpourri of Reporting Tips
Question: How do I convert a numeric column to a string?

Answer: Create a Crystal Reports formula that uses the Crystal Reports ToText function, which converts numeric data to string. The function also contains overloads, allowing me to specify the number of decimals in the return string. This helps in instances where I have a value of 123.00 and want to return a string that reads "123".

Question: How can I display a column of data in a different color, based on some condition?

Some developers view reports as busy work. But they are the bridge between the data that you see, and the information that clients and users expect from the system.
Answer: Create a Crystal Reports formula that compares the column to another threshold column, and then returns a Crystal Reports constant for the color. Insert the formula into the report by doing the following:

  1. Right-click the column and choose Format Field.
  2. In the Format Editor, click the Font tab.
  3. On the Font tab, click the formula icon to the right of the Font color option.
  4. In the formula editor, insert the following code:
   if {MyData.Costs} > MyData.CostThreshold} then
Question: How can I save the image of generated reports, in an audit trail fashion, so that anyone can go back and see what was actually generated at the time?

Answer: One technique is to automatically save the report as PDF to a shared location when the user prints the report. The library in Tip 3 makes this process very easy. You can create a database table that logs each instance (who generated the report, when, the name of the PDF, etc.)

Question: How do I programmatically set print options beyond those specified in my print library?

Answer: Access the print options class inside the report object. Here's a code sample that shows some different possibilities:

   using CrystalDecisions.Shared;
      RPT_Invoice oRpt = new RPT_Invoice();
      oRpt.PrintOptions.PrinterName = "printer name";
      oRpt.PrintOptions.PaperSize = PaperSize.Paper10x14;
      oRpt.PrintOptions.PaperSource =  PaperSource.Envelope;
      oRpt.PrintOptions.CustomPaperSource = PaperSource.Envelope;
      oRpt.PrintOptions.PaperOrientation = 
Have you ever submitted something (an article, a paper, some code, etc.) and thought of some good ideas after the fact? Well, I'm the king of thinking of things afterwards. Fortunately, that's the type of thing that makes blogs valuable. Check my blog for follow-up tips and notes on Baker's Dozen articles…and maybe a few additional treats! You can find the entire source code on my Web site.

Kevin S. Goff is the founder and principal consultant of Common Ground Solutions, a consulting group that provides custom web and desktop software solutions in .NET, Visual FoxPro, SQL Server, and Crystal Reports. Kevin has been building software applications for 17 years. He has received several awards from the U.S. Department of Agriculture for systems automation. He has also received special citations from Fortune 500 companies for solutions that yielded six-figure returns on investment. He has worked in such industries as insurance, accounting, public health, real estate, publishing, advertising, manufacturing, finance, consumer packaged goods, and trade promotion. In addition, Kevin provides many forms of custom training.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date