Customizing the Appearance and Layout of the Report Viewer
The CrystalReportViewer class contains all of the properties, methods, and events that relate to the viewer itself; its appearance, methods that are used to make the viewer perform certain actions (such as refresh or go to the next page), and events that can be used to determine when a particular event (such as drill-down or refresh) has occurred. To start learning how to work with the viewer, we are going to start with the basic properties and move on from there.
To get started, we need to create a new project to work in - from within Visual Studio, select File | New | Project and from Visual Basic Applications, select ASP.NET Web Application and specify a name and location for your project files.

In the sample files, we have called this project (web_viewer_properties). Once you have selected a name for your project and clicked OK, the development environment will open with a default form that we will be using in the section. Alternatively, you can create a virtual directory for this project using the sample code provided.We also need to add a report to work with in this section, so select Project | Add Existing Item and select product_listing_bytype.rpt. Add this to your project, insert the CrystalDecisions.CrystalReports.Engine namespace, drag across a ReportDocument and place this on the form (selecting product_listing_bytype.rpt out of the options on the dialog box), and then insert the CrystalReportViewer and set the binding to this report in the Page_Init event:
CrystalReportViewer1.ReportSource = product_listing_bytype1
You are now ready to get started!When you were working through the earlier example, binding to a viewer and previewing your report, you may have noticed that there is a standard set of icons and layout that appears by default on the CrystalReportViewer. You can control most of the aspects of the viewer and toolbar by setting a few simple properties, as shown overleaf.

The area at the top of the viewer is the toolbar, which can be shown or hidden as an entire object or you can choose to only show certain icons. On the left-hand side is a Group Tree, generated by the grouping that you have inserted into your report. The properties that control these general properties are Boolean and are listed below:
Property
Description
BestFitPage
For showing the report as-is or with scroll-bars
DisplayGroupTree
For showing the group tree on the left-hand side of the viewer
DisplayPage
For showing the page view
DisplayToolbar
For showing the entire toolbar at the top of the viewer
SeperatePages
For displaying a report in separate pages or one long page
All of these properties default to True and you cannot change the position of any of these elements - they are fixed in place on the viewer. You can, however, hide all of these icons and create your own buttons for printing, page navigation, and so on.For the icons within the toolbar, you can also set simple Boolean properties to show or hide a particular icon, as shown below:
HasDrillUpButton
HasGotoPageButton
HasLevelUpButton
HasPageNavigationButtons
HasRefreshButton
HasSearchButton
HasZoomFactorList
So a typical use of these properties is where you want to give users a preview of the report with the ability to refresh the data shown. You could easily set a few properties before you set your ReportSource property to make this happen:
CrystalReportViewer1.HasRefreshButton = true
When the report is previewed, it will appear as shown:

In addition to simple Boolean properties, there are also a couple of other properties that can be set to control the appearance and behavior of the viewer, including:
Property
Description
PageToTreeRatio
For setting the ratio between the group tree and the rest of the page -larger numbers mean a larger report page, with a smaller group tree
PageZoomFactor
The initial zoom factor for the report when viewed
So if we wanted to change the PageToTreeRatio and zoom factor so that the report was presented a little bit better on the page, we could add the following code to be evaluated when the page was loaded:
CrystalReportViewer1.PageToTreeRatio = 7
CrystalReportViewer1.PageZoomFactor = 80
Our previewed Web Form would look like this:

Viewer Methods
When working with the CrystalReportViewer, we have a number of methods available to us, which will allow us to integrate specific viewer functions into our application. As we move through this section, keep in mind that these methods can be used to create your own "look and feel" for the report preview window.
Create a new Web Form, which we'll call web_viewer_methods. Again, the code for this application is included with the download code. Drag a CrystalReportViewer onto this form. Include the report product_listing_bytype.rpt in your project (in the download code, the path is CrystalReports/Chapter04/product_listing_bytype.rpt). Drag a ReportDocument component from the Toolbox onto your form, and when the dialog box opens up, select web_viewer_methods.product_listing_bytype from the drop-down box. Click OK.Now we add some code to tie our report to the application. In the Page_Init event in the designer generated code, once again add:
CrystalReportViewer1.DataBind()
Now all that remains is to set the ReportSource property in the Page_Load sub:
CrystalReportViewer1.ReportSource = product_listing_bytype1
Compile and run this. Now, we're all set to customize our viewer.In this example, we are actually going to walk through building a custom viewer. The first thing we need to do is set the DisplayToolbar property and the DisplayGroupTree property to False in the Properties pane for the viewer, and add some additional buttons and textboxes to our Web Form using the screen shot earlier as a guide, which we will walk through below.As we walk through this example, we are going to add the code behind these buttons and this form using the methods described below and learn how to match the viewer user interface to your own application.
Setting Browser Rendering
The CrystalReportViewerBase class provides a number of key properties, one of which is the ClientTarget. The ClientTarget property is a string and determines how the Crystal Report Viewer will render the report.These strings are:
ie4 - for Internet Explorer 4.0
ie5 - for Internet Explorer 5.0
uplevel - for most other web browsers
downlevel - for very basic web browsers
A web browser is considered uplevel if it can support the following minimum requirements:
ECMAScript (JScript, JavaScript) version 1.2.
HTML version 4.0
The Microsoft Document Object Model (MSDOM)
Cascading style sheets (CSS)
Browsers that fall into the downlevel category include those browsers that only provide support for HTML version 3.2.So, to set the browser version you are targeting, you could set the ClientTarget property for your form like this, under the Page_Load subroutine:
CrystalReportViewer1.ClientTarget = "ie4"
There is also an Auto value, which is the default setting and automatically selects the best rendering option based on the browser type. Unless you are writing an application for a specific browser or compatibility level, leaving this property set to Auto will provide the best viewing experience for the browser you are using.
Important
For more information on detecting the browser type your web application is using, see the topic "Detecting Browser Types in Web Forms" in the Visual Studio .NET combined help collection.
Refreshing the Data in a Report
When a report is refreshed, it goes back to the database for the most current set of data available and runs the report again. On our custom web viewer, you should have a Refresh button, so pull a Button control onto the Web Form and rename it Refresh_Button in the ID property in the Properties pane. Change the text property to Refresh.Now, click on the Refresh_Button on your form to open the code for it. We can add some code behind this button to refresh the report using the RefreshReport method as shown below:
Private Sub Refresh_Button_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Refresh_Button.Click
CrystalReportViewer1.RefreshReport()
End Sub
Compile and run the application. The button should now be present on your form. Click on it. This will cause the report to return to the database and read the records again. Use this functionality with caution - if a report has a large SQL query to perform before it can return the first page, you may experience performance problems.
Page Navigation and Zoom
Now we are going to insert some buttons across the top of our Web Form in the same way we did with the Refresh button, with the following names and text values:
Button Name (ID Property Value)
Text Property Value
FirstPage_Button
First
Back_Button
Back
Forward_Button
Forward
LastPage_Button
Last
We access these properties, once again, through the Properties pane in Visual Studio .NET.For page navigation using the buttons we have drawn on our custom form, we have a number of methods that can be called without any additional parameters, as shown below:
ShowFirstPage
ShowPreviousPage
ShowNextPage
ShowLastPage
These methods do not return a result, and unlike the Windows Forms Viewer, the Web Form Viewer does not have a GetCurrentPageNumber method, which would have returned an integer representing the page you are currently viewing.To add these methods to the page navigation buttons, double-click the appropriate buttons on your Web Form and enter the code behind, as shown:
CrystalReportViewer1.ShowNextPage()
Do this for the other three buttons, including the appropriate method for each. Compile the project and test these buttons.In addition to page navigation, you also have the ability to choose the zoom factor that is applied to your report. By default, the zoom is set to 100% of the report size unless you specify otherwise.In our custom viewer, you should have a drop-down list for the zoom factor. To create our own zoom factor functionality, drag a drop-down list onto the form. Open the properties for your drop-down list (in our example, we have named the drop-down list ZoomList).In the properties for your drop-down list, locate and open the Items property, which should open the dialog shown here:

Using this dialog, we are going to create the items that will appear in our drop-down list and specify the corresponding values that will be passed to the form when an item is selected. Use the Add button to add items and make sure that the values correspond to the text you have entered (for instance, Full Size = 100, 50% = 50, and so on).Once you have entered all of the values, click OK to accept these changes and return to your form's design. To use the Zoom method, double-click your drop-down box and add the following code:
CrystalReportViewer1.Zoom(DropDownList1.SelectedItern.Value)
This is simply calling the Zoom method using the item the user selects from your drop-down box. When you run your application and preview your custom viewer, you should be able to select your own zoom factor, and have it appear in the browser by pressing the Refresh button, as shown here:

Searching within a Report
Another powerful navigation feature can be found in the SearchForText method within Crystal Reports.NET, which will allow you to search for a specific string that appears in your report.On our custom viewer, we are going to create a textbox and a button labeled Search. We are going to use this textbox to enter some search string and when the user clicks the Search button, we are going to use the SearchForText method to find the search string within our report.To start, we will call our textbox TextBox_SearchString and our Search button Search_Button. Add these to the design view of our Web Form, remembering to replace the Text property for the button with Search.To use the SearchForText method, double-click the Search button and add the following code behind:
Private Sub Search_Button_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Search_Button.Click
If TextBox_SearchString.Text <> " Then
CrystalReportViewer1.SearchForText(TextBox_SearchString.Text, _
CrystalDecisions.[Shared].SearchDirection.Forward)
End If
TextBox_SearchString.Text = " "
End Sub
The Crystal Report Viewer will search the entire report and when the value is found, go directly to the page on which it appears (the last line of code above is just to clear the textbox for the next search) This method can be called repeatedly to find all of the occurrences of a particular string - each time it finds the string in your report (in our example below, we searched for Youth Helmet), it will jump to that page, as shown below:

Important
You may have noticed that this method is slightly different between the Windows and web viewers for Crystal Reports: with both types of Forms Viewer, you can pass the additional parameter of Search Direction for searching forwards or backwards through your report. However, in addition, this method in Windows will highlight the found value. The web version does not have this capability.
Printing Your Report
Now, if you have already done some report integration with Windows applications, you may have noticed that the Web Forms Viewer is missing one very important icon - the Print button. When a Crystal Report is viewed on the web, it is actually rendered in static HTML 3.2 or HTML 4.0, with all of the report elements represented in HTML code and syntax.
This makes things difficult when it comes time to print your report - in a case where you were just using the plain old viewer with little or no modification, imagine if you were to click on the print button from your browser to print your report. Here is a preview of what your printed report would look like:

It is not very pretty to say the least - if your application uses single-page reports or discrete parts of a report, you may be happy with this, but for the rest of us, there has to be a better solution. So in answer to this limitation in HTML and the way reports are presented in a browser window, we have to come up with some creative solutions to actually print our report to a printer.The following sections detail the different ways a report can be printed from the Web, as well as some of the advantages and drawbacks of each method. Since we are looking at new functionality within Crystal Reports.NET, we are going to create a new project specifically for this section.From within Visual Studio, select File | New | Project and from Visual Basic Applications, select ASP.NET Web Application and call this new application web_viewer_print. This application is included with the download code. To use the downloaded version a virtual directory should again be created for it in its downloaded location.

Once you have clicked OK, the development environment will open with the default form that we will be using in the section.We also need to add a report to work with in this section, so select Project | Add Existing Item. Change the drop-down list to show All Files and specify *.rpt for the file name to filter the list to show only the available reports. The web_printing_report.rpt file is in the code download path CrystalReports\Chapter04\web_printing_report.rpt.Once you have selected the web_printing_report.rpt report, click Open and this report will be added to your project in the Solution Explorer - we will be looking at the different methods for printing this report in the following sections.Now, simply drag a ReportDocument component onto the form, which should offer you web_viewer_printing.web_printing_report as first choice in the drop-down box. Select it and drag a CrystalReportViewer onto the Web Form. Now, to bind the ReportDocument component to the viewer, merely enter the following code in the Web Form's Page_Init event, as we have done more than once in this chapter:
CrystalReportViewer1.ReportSource = New web_printing_report()
Compile and run the application to check that everything is working. We are now ready to start looking at printing this report.
Printing from the Browser
The simplest method for printing a report is to print directly from the browser. You have already seen how well this works, but there are some tricks that we can use to improve the way the report prints if we are forced to use this method.First of all, you can disable the DisplayGroupTree property if the report is likely to be printed. Do this by setting it to False in the Properties window, or you could do this programmatically by inserting the following code into the Page_Load event:
CrystalReportViewer1.DisplayGroupTree = False
The viewer object model provides a property called SeperatePages that by default is set to True, meaning that the report is chunked up into individual HTML pages based on the report pagination.When this property is set to False, the report itself becomes one long page, which can then be printed just like any other web page. You can set this property through the property page of the Crystal Report Viewer, as shown here:

or you can also set this option programmatically:
CrystalReportViewer1.SeparatePages = False
Another trick is to actually turn off the toolbar and all of the icons so that the output on the page is close to what you would like to see when the report is printed.
CrystalReportViewer1.DisplayToolbar = False
So with the toolbar turned off and our report showing as one long page, you can then print your report and have a somewhat-decent output as shown here in a preview from Internet Explorer:

The only problem is that this method does not take advantage of any of the neat formatting features for page headers and footers, as the browser just thinks this is one big page to be printed. In addition, the column headings are only printed on the first page, so it is difficult to read the report as you move through the pages.
NoteThis method is only recommended for reports with a small number of pages (1-20) as the entire report is concatenated into one long page, which may take a while to render on screen or print.
However, with that said, printing from the browser is the easiest method of printing your report from the web, even with its limitations. For report developers who have put a lot of time and effort into their report design and want that report to be seen and printed by the users (and look good!) we need to look at another solution.
Printing from the Adobe Acrobat Plug-In
Crystal Reports.NET supports many export formats, and one of the more popular ones is Adobe's Portable Document Format or PDF. Using the export functionality within Crystal Reports.NET and a copy of Adobe Acrobat Reader (or the plug-in) installed on the client machine, reports can be printed from the web.This is one of the methods recommended by Crystal Decisions for printing your reports in a presentation-quality format, and it actually developed the workaround used in this section to help developers who were used to the way Crystal Reports normally operates and were frustrated by not having that print button.The first thing we need to do is create a new Web form that will contain our instructions. We will call this form AcrobatPrinter.aspx, and create it by right-clicking on the project name, and selecting Add | Add New Item. We will then select Web Form and name it as above. Right-click on it and select Set as Start Page.Draw or drag a button onto the Web form and call it PDF_Button, and label it Export via PDF.Now we need to do some setup to utilize the Crystal Reports Engine (covered in Chapter 8) and set some options available from the CrystalDecisions.Shared namespace.So, we are going to put some code behind our export button to dimension variables for the export options that we want to use, and also for the specific options for exporting to a disk file. Click on the button in the designer, and insert the following code:
Private Sub PDF_Button_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles PDF_Button.Click
Dim myExportOptions As CrystalDecisions.Shared.ExportOptions
Dim myDiskFileDestinationOptions As _
CrystalDecisions.Shared.DiskFileDestinationOptions
Next, we are going to create a variable to hold the name of the file that we are going to be exporting to, as well as creating a new instance of a Sales Report that has already been added both to the project and to this form, through the ReportDocument component.
Dim myExportFile As String
Dim myReport As New web_printing_report()
For our next order of business, we need to set a temporary location for the output file - this can be anywhere on your server - and we are going to build a unique file name using the session ID from the ASP.NET session and tacking the PDF extension on the end, so the file association will work correctly when we go to view this file in our browser.
myExportFile = "C:\CrystalReports\Chapter04\PDF " & _
Session.SessionID.ToString & ".pdf"
Now, for the meat of the matter - actually setting the destination options to export your report to a PDF file and write it to the disk.
myDiskFileDestinationOptions = New
CrystalDecisions.Shared.DiskFileDestinationOptions()
myDiskFileDestinationOptions.DiskFileName = myExportFile
myExportOptions = myReport.ExportOptions
With myExportOptions
.DestinationOptions = myDiskFileDestinationOptions
.ExportDestinationType = .ExportDestinationType.DiskFile
.ExportFormatType = .ExportFormatType.PortableDocFormat
End With
Then, we call the Export method to export our report:
myReport.Export()
But we are not done yet! We need to take the exported PDF file that has been generated and output it to the browser so the user can view it using the Acrobat Plug-In or standalone viewer. To do that, we are going to use some simple response statements to return the file to the browser:
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/pdf"
Response.WriteFile(myExportFile)
Response.Flush()
Response.Close()
Finally, once we have delivered the file to the user, we need to clean up after ourselves and remove the file from the server altogether.
System.IO.File.Delete(myExportFile)
End Sub
So when all of this code is put together behind our export button and our application is run, the user can click the button and preview and print the report from Adobe Acrobat, with the page numbering and other features in place, as shown here:

Printing from other Export Formats
In addition to Adobe Acrobat format, you can also print to other supported export formats such as Excel, Word, or others, by changing the file extension, the MIME type, and the ExportFormatType property in the code above. There are a number of different destinations that are supported, including:
Name
Description
MIME Type
Excel
To export to a Microsoft Excel fileapplication/vnd.ms-xls
HTML32
To export to an HTML file compatible with HTML v3.2application/html
HTML40
To export to an HTML file compatible with HTML v4.0application/html
PortableDocFormat
To export to PDF (Acrobat) formatapplication/pdf
RichText
To export to an RTF file for use with Microsoft Word, WordPerfect, and so onapplication/rtf
WordForWindows
To export to a Microsoft Word fileapplication/msword
If you want to export to Word, the RTF export actually provides a better export format. To open the RTF on the client side using Word (instead of the application associated with the RTF file extension), leave the ExportFormatType property set to RichText but change the MIME type to be application/msword.
Using Viewer Events
Viewer events provide the ability to track when different events are fired from the browser - for instance, when the user navigates through the pages of the report or when they refresh the report. These events can then be used to fire other code within your application.While all of the different events have their own unique properties and methods, they all inherit a common property called Handled that is a Boolean value used to determine whether the event was fired and subsequently handled.In the following section, we will be looking at all of the available events associated with the viewer and their common use - if you would like to try out some of the events listed below, open the custom viewer we were working with earlier in the chapter (WebForm1.aspx from the project web_viewer_properties) and add a label to your form (call it Event_Label) - we'll use this label to notify the user when an event is fired. Clear its Text property. Now we are ready to begin.
Page Navigation Events
For page navigation, the NavigateEventArgs class provides the properties we need to work with the Navigate event, including:
Property
Description
CurrentPageNumber
Returns the current page number
NewPageNumber
Gets or sets the new page number
In the example below, the Navigate event would fire when a user changed the page within the viewer, resulting in a label that would show the page they are coming from and the page they are navigating to.Insert the following subroutine into your Web Form code:
Private Sub CrystalReportViewer1_Navigate(ByVal source As Object, ByVal
MyEvent As CrystalDecisions.Web.NavigateEventArgs) Handles
CrystalReportViewer1.Navigate
If MyEvent.NewPageNumber <> 1 Then
Event_Label.Text = "Current page: " & MyEvent.CurrentPageNumber & _
" New Page: " & MyEvent.NewPageNumber
End If
End Sub
So, as the user navigates through the pages, this information is shown and can be used in your application. Compile and run this code to see this happen.
Refresh Events
The ReportRefresh event has no arguments other than the inherited Handled property. It can be used to build metrics on how often a report is run or refreshed, and to pass information to users about the report before they launch a refresh, as shown below:
Private Sub CrystalReportViewer1_ReportRefresh(ByVal source As Object,
ByVal MyEvent As CrystalDecisions.Web.ViewerEventArgs) Handles
CrystalReportViewer1.ReportRefresh
Event_Label.Text = "Please be advised this report takes up to 2 minutes
to run."
End Sub
Insert this subroutine into your Web Form code, in the same way as we did above. Compile and run. The message should now appear in the label when you hit Refresh.
Search Events
When a user searches for a report value, either through the standard icon on the toolbar or through your own method call, the Search event is fired. The arguments for the Search event are:
Property
Description
Direction
Gets or sets the direction in which to search. This can be either Backward or Forward.
PageNumberToBeginSearch
Gets or sets the page number to start searching at.
TextToSearch
Gets or sets the text to search for in the report.
So by using these event arguments, you could keep a record of what values users searched for or offer a "Top Ten" search facility to let them search using the ten most requested search strings. An example of getting the text that is being used in the search is included below - insert this subroutine into your code, build and run it:
Private Sub CrystalReportViewer1_Search(ByVal source As Object, ByVal
MyEvent As CrystalDecisions.Web.SearchEventArgs) Handles
CrystalReportViewer1.Search
Event_Label.Text = "You searched for " & MyEvent.TextToSearch
End Sub
Zoom Events
When the user changes the zoom factor for a particular report, the ViewZoom event fires, and has only one argument, ZoomEventArgs. The NewZoomFactor property will get or set the magnification factor for the viewer, as shown here:
Private Sub CrystalReportViewer1_ViewZoom(ByVal source As Object, ByVal
MyEvent As CrystalDecisions.Web.ZoomEventArgs) Handles
CrystalReportViewer1.ViewZoom
Select Case MyEvent.NewZoomFactor
Case "25"
Event_Label.Text = "You have selected 25%"
Case "50"
Event_Label.Text = "You have selected 50%"
Case "100"
Event_Label. Text = "You have selected full size"
End Select
End Sub
NoteFor further customization of your report and control of your report's features and functionality, you may want to turn to Chapter 8 to learn how to work with the Crystal Reports Engine, which provides control over your report at run time.