≡ Menu
Deep in the Code

Fixing the CrystalReportViewer “Next Page” Navigation Problem

Note: This is an update to my last post.

I discovered that the version of the SAP CrystalReportViewer for VS2010 (13.0.2000.0) that I am using appears to have a bug that prevents the user from proceeding past page 2 when using the Next Page button. Pages can still be directly accessed by typing in the page number, but clicking the Next Page button keeps you on page 2.

I read quite a few possible solutions to this, such as moving the code that loads the Crystal Report from Page_Load to Page_Init, but this did not work for me. Also, there is an update to 13.0.2000.0 that might fix this issue, but I am not in a position to update the version of the SAP Crystal Reports software at present.

Fortunately, I was able to code around this bug. First, I disabled the navigation buttons on the viewer itself. Next, I put my own navigation buttons above the viewer component on the ASP.NET Web Form. Lastly, I wrote the code that handles the click events for these buttons.

Here is the code for the Reports.aspx page:

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Reports.aspx.vb" Inherits="Pages_Reports" %>

<%@ Register Assembly="CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"
    Namespace="CrystalDecisions.Web" TagPrefix="CR" %>

<!DOCTYPE html>

<html>
    <head runat="server">
        <title></title>
        <meta http-equiv="X-UA-Compatible" content="IE=9,chrome=1" />
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server" AsyncPostBackTimeout="0" EnableHistory="True">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                <ContentTemplate>
                    <asp:Label ID="Label1" runat="server" Text="Page navigation:   "></asp:Label>
                    <asp:Button runat="server" ID="btnFirst" 
                        Text="|<--" ToolTip="Go to first page"/>
                    <asp:Button runat="server" ID="btnPrev" 
                        Text="<<" ToolTip="Go to previous page"/>
                    <asp:Button runat="server" ID="btnNext" 
                        Text=">>" ToolTip="Go to next page"/>
                    <asp:Button runat="server" ID="btnLast" 
                        Text="-->|" ToolTip="Go to last page"/>
                    <CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server" AutoDataBind="true"                     
                    HasCrystalLogo="False" GroupTreeStyle-ShowLines="True" 
                        Width="100%" Height="100%" 
                    EnableDatabaseLogonPrompt="False" ReuseParameterValuesOnRefresh="True" 
                        HasPageNavigationButtons="False" ShowAllPageIds="True" 
                        EnableParameterPrompt="False" />                    
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
        </form>
    </body>
</html>

…and the code file Reports.aspx.vb…

Imports CrystalDecisions.Shared
Imports System.IO
Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Web

Partial Class Pages_Reports
    Inherits System.Web.UI.Page

    Protected strQueryString As String
    Protected intLastPage As Integer
    Protected intCurPage As Integer

    Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
        strQueryString = Request.QueryString.ToString()
        Page.Title = Replace(Request.QueryString("rpt").ToString(), ".rpt", "")
        If Not Page.IsPostBack Then
            'Do nothing
        ElseIf Session(strQueryString) IsNot Nothing Then
            CrystalReportViewer1.ReportSource = Session(strQueryString)
        End If
    End Sub

    Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            Dim strReportName As String = Request.QueryString("rpt")
            Dim strSingleDate As String = Request.QueryString("single")
            Dim strBeginDate As String = Request.QueryString("begin")
            Dim strEndDate As String = Request.QueryString("end")

            Dim bSingleDate As Boolean = False
            Dim bMultiDate As Boolean = False

            Dim arrSingleDate() As String = _
               Utilities.AppSettingsFunction.getValue("SingleDate").Split(",")
            Dim arrMultiDate() As String = _
               Utilities.AppSettingsFunction.getValue("MultiDate").Split(",")

            If Array.IndexOf(arrSingleDate, strReportName) <> -1 Then
                bSingleDate = True
                bMultiDate = False
            ElseIf Array.IndexOf(arrMultiDate, strReportName) <> -1 Then
                bSingleDate = False
                bMultiDate = True
            End If

            Dim connInfo As New ConnectionInfo
            Dim rptDoc As New ReportDocument

            'setup the connection
            connInfo = Functions.GetConnectionInfo()

            'load the Crystal Report
            rptDoc.Load(Server.MapPath( _
               Utilities.AppSettingsFunction.getValue("ReportFolder") _
               & strReportName))

            'apply logon information
            For Each tbl As CrystalDecisions.CrystalReports.Engine.Table In rptDoc.Database.Tables
                Dim repTblLogonInfo As TableLogOnInfo = tbl.LogOnInfo
                repTblLogonInfo.ConnectionInfo = connInfo
                tbl.ApplyLogOnInfo(repTblLogonInfo)
            Next

            'add required parameters
            If bSingleDate Then
                rptDoc.SetParameterValue("REPORT_DATE", strSingleDate & " 23:59:59")
            End If

            If bMultiDate Then
                rptDoc.SetParameterValue("BEGIN_DATE", strBeginDate & " 00:00:00")
                rptDoc.SetParameterValue("END_DATE", strEndDate & " 23:59:59")
            End If

            'Set, bind, and display Crystal Reports Viewer data source
            Session(strQueryString) = rptDoc
            CrystalReportViewer1.ReportSource = Session(strQueryString)
            CrystalReportViewer1.ShowLastPage()
            CrystalReportViewer1.ShowFirstPage()
            Session(strQueryString + "_pagenum") = 1
            Session(strQueryString + "_lastpagenum") = GetLastCRPageNumber()
        ElseIf Session(strQueryString) IsNot Nothing Then
            CrystalReportViewer1.ReportSource = Session(strQueryString)
        End If
        GetPageNums()
    End Sub


    Private Sub GetPageNums()
        intCurPage = Session(strQueryString + "_pagenum")
        intLastPage = Session(strQueryString + "_lastpagenum")
        ButtonsCheck()
    End Sub

    Private Sub SetCurPageNum(intPage As Integer)
        GetPageNums()
        Session(strQueryString + "_pagenum") = intPage
        ButtonsCheck()
    End Sub

    Protected Sub btnNext_Click(sender As Object, e As System.EventArgs) Handles btnNext.Click
        GetPageNums()
        If intCurPage < intLastPage Then
            SetCurPageNum(intCurPage + 1)
            CrystalReportViewer1.ShowNthPage(intCurPage + 1)
        Else
            CrystalReportViewer1.ShowNthPage(intCurPage)
        End If
    End Sub

    Protected Sub btnPrev_Click(sender As Object, e As System.EventArgs) Handles btnPrev.Click
        GetPageNums()
        If intCurPage > 1 Then
            SetCurPageNum(intCurPage - 1)
            CrystalReportViewer1.ShowNthPage(intCurPage - 1)
        Else
            CrystalReportViewer1.ShowNthPage(intCurPage)
        End If
    End Sub

    Private Function GetCRPageNumber() As Integer
        Dim vi As ViewInfo = CrystalReportViewer1.ViewInfo
        Return vi.PageNumber
    End Function

    Private Function GetLastCRPageNumber() As Integer
        Dim vi As ViewInfo = CrystalReportViewer1.ViewInfo
        Return vi.LastPageNumber
    End Function

    Protected Sub ButtonsCheck()
        If intCurPage = 1 Then
            btnFirst.Enabled = False
            btnPrev.Enabled = False
        Else
            btnFirst.Enabled = True
            btnPrev.Enabled = True
        End If

        If intCurPage = intLastPage Then
            btnLast.Enabled = False
            btnNext.Enabled = False
        Else
            btnLast.Enabled = True
            btnNext.Enabled = True
        End If
    End Sub

    Protected Sub CrystalReportViewer1_Navigate(source As Object, e As CrystalDecisions.Web.NavigateEventArgs) Handles CrystalReportViewer1.Navigate
        SetCurPageNum(e.NewPageNumber)
    End Sub

    Protected Sub btnFirst_Click(sender As Object, e As System.EventArgs) Handles btnFirst.Click
        CrystalReportViewer1.ShowFirstPage()
        GetPageNums()
    End Sub

    Protected Sub btnLast_Click(sender As Object, e As System.EventArgs) Handles btnLast.Click
        CrystalReportViewer1.ShowLastPage()
        GetPageNums()
    End Sub
End Class