To create a new project, select the "Crystal Reports
WPF Application" from the new projects menu. It can be found under the
Reporting category of your installed templates. After creating the project,
the new solution has a WPF class, and a Crystal Report should be visible in the
Solution Explorer. That WPF file has a WPF Crystal Viewer bound to it. Let me
warn you that creating a WPF solution from Visual Studio templates then trying
to add the Crystal viewer to that solution is tricky to implement. It is much
easier to just use the templates provided from SAP.
The new WPF viewer control to use in your windows
applications is a slick new control. It looks better and has some newer
features, as revealed in the API section above. Binding a report to the viewer
is done most easily programmatically.
If you want to allow the end user some control of what
report to view, enable the property ShowOpenFileButton to allow the user to
select a report. Eventually there will be a property to set this, but you can
set the report to an embedded resource using code. For instance, in example 1,
the code shows how to bind an embedded resource to the report viewer.
CrystalReport1 is a report created in a project. To bind
this report to the new WPF viewer, use the property ViewerCore.ReportSource and
set it to the instance of the embedded report. Code Sample 1 shows the code.
Code Sample 1
InitializeComponent();
reportViewer.Owner = this;
CrystalReport1 newCR = new CrystalReport1();
reportViewer.ViewerCore.ReportSource = newCR;
Once you have set the code to bind this report to your
viewer, you are now ready to use some of the new WPF properties. Let's go
through each property and find the methods where it is best to use them.
NumberOfPages
Once you have set up a CR Project and created the initial
code to bind your report, you can now start experimenting with the new API
methods and events available to you. All of these properties are from the ReportRequest
class and will return some data available from the Report document being
rendered. In this case we start with ReportDocument.ReportRequestStatus.NumberOfPages
In working with this method, it appears that until the
report has been renedered, this method will only return a 0. Once rendered,
then the number of pages in total that the report has will be returned.
For example, the code displayed in the LayoutUpdated method
of the viewer (see this in code example 2), fires multiple times during startup.
Hovering over this method in debug mode until the viewer renders the report, we
see that the count is 0. This can be a useful way to programmitcally get page
numbers from reports with large datasets that vary.
Code Sample 2
Private void reportViewer_LayoutUpdated(object sender, EventArgs e)
{
Int numPages = newCR.ReportRequestStatus.NumberOfPages;
}
Use this after LayoutUpdated, or Refresh to determine how
many pages are now displaying in the viewer.
NumberOfRecordsRead
This property can be used, in the event LayoutUpdated, and is
populated after parameters are filled out. Other events where this can be
useful are in the Refresh, and RequestBringIntoView event.
As noted above, the LayoutUpdated method fires multiple
times during loading of the report. Only after the parameter is selected have
I found that this property is populated. Since the Viewer event Loaded fires
before parameters are selected, this property is not populated during that
event.
This property can be useful during events like RequestBringIntoView,
and Refresh also. Any event that fires after these should also be able to
utilize this property. This could be helpful during backend processing, if you
are writing logs, or if any kind of error is encountered to help troubleshoot
those kind of issues.
Code Sample 3
Private void reportViewer_LayoutUpdated(object sender, EventArgs e)
{
Int numPages = newCR.ReportRequestStatus.NumberOfPages;
Int numRecordsRead = newCR.ReportRequestStatus.NumberOfRecordsRead;
}
NumberOfRecordsSelected
This property is very similar to NumberOfRecordsRead. In
fact in the course of this article, the results from this property were not
different than that of NumberOfRecordsRead for the Refresh,
RequestBringIntoView, Loaded, SelectionChanged and LayoutUpdated methods. While
there may be a difference and a good place to utilize this, it is not within
these methods.
Below is some sample code for how you can utilize this
property. It is very similar to NumberOfRecordsRead.
Code Sample 4
Private void reportViewer_SelectionChange(object sender, RoutedEventArgs e)
{
Int numRecordsSelecteds = newCR.ReportRequestStatus.NumberOfRecordsSelected;
}