RDLC报表

来源:互联网 发布:淘宝买药品不能付款 编辑:程序博客网 时间:2024/05/21 15:25

VS .NET开发中,用什么做报表?

    可能的回答是Crystal Report,自.NET“紧密集成Crystal Report后,这可能是开发人员比较单一的选择。但是,这种集成似乎并不非常紧密,网络上充斥着关于使用Crystal Report的抱怨,太复杂也许是其最为令人诟病的地方,自定义性比较差也不能为程序员们所容忍。

    当然,必须承认Crystal Report的功能还是非常强大的,被Business Object收购以后,商业职能的成分也在逐渐增加,也形成了一定规模的用户群。

    Visual Studio .NET进入2005版本以后,Crystal ReportIDE的结合更紧密了,至少我们看不到那个讨厌的注册窗口了。但是,Microsoft似乎并不容忍在自己的超级工具中竟然没有报表工具,于是Report Viewer Control出现了,我把它的报表称为RDLC报表。

    VS .NET 2005之前,SQL Server Reporting Services中已经提供了一种被称为报表定义语言(Report Definition Language, RDL)的语言;在VS .NET 2005中,Microsoft提供了针对这种报表的设计器,并提供了在WinFormWebForm中使用这种报表的能力。Microsoft将这种报表的后缀定为RDLCRDL仍然是Report Definition Language的缩写,那么C代表什么呢?C代表Client-side processing,凸显了它的客户端处理能力。

    这种报表的易用性和可定制性让我们完全有理由放弃Crystal Report,让我们来看看它的强大功能吧:
    1
、简单易用的控件,特别是Table控件,非常方便字段在报表上的排列;
    2
、灵活的可定制性,用XML来描述一个报表相关的一切,不用说了吧?
    3
、高度可编程性,在你的项目中,甚至不需要有一个报表文件,通过代码就可以实现报表生成、预览和打印等一系列操作;
    4
、支持DrillThrough数据钻取功能;
    5
、导出的Excel文件格式非常完美,任何其它报表在这方面都不能与之比拟,而且并不需要安装Excel
      ……[
偷偷懒,其实我并不擅长总结某某的特点,我只能从实际经验中得到一点点结论,而且我也不原意去抄袭帮助中的New Features,呵呵……]

     在以后的几篇随笔中,我将结合最近一段时间使用RDLC报表的经验继续探讨相关的一些问题,大致内容包括:报表设计器的使用、LocalReport的一些相关操作,如何自定义纸张等等,欢迎大家提出参考意见。

     需要说明的是,现在关于VS. NET 2005中的Report Viewer Control的内容非常少,我只能按照自己的理解来说一些东西,这其中肯定会有一些偏差,欢迎各位的批评指正。另外,我所涉及的内容都是关于LocalReport的,对于ServerReport没有进行研究。
相关的资源:

    MSDNVisual Studio Controls论坛  http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=75&SiteID=1 
    GotReportViewer   http://www.gotreportviewer.com/
(有几个非常经典的例子,不知为什么最近我无法上这个网站了,呵呵,谁知道请告诉我原因,谢谢!)

晕死,总是见到朋友们评论要GotReportViewer的实例,请在下面的连接中下载:http://files.cnblogs.com/waxdoll/RDLC.rar

    在这篇随笔中,我主要分析一下GotReportViewer上的几个经典例子,我们可以从中看到ReportViewer Control的强大功能:
    1
Web Log Analyzer    
    
这是一个比较典型的OLAP应用,我们可以看到RDLC报表强大的ChartNavigation功能。当然了,例子中解析W3C标准日志文件的代码也非常有借鉴意义。这个Starter Kit在我的随笔http://waxdoll.cnblogs.com/archive/2006/01/19/320280.html中曾经提到过,不再详述。  
    2
、子报表  
    
展示如何使用子报表显示主记录的详细信息,这种应用很像Access中的子报表功能。主要使用SubreportProcessing事件为子报表提供数据。  
    3
、钻取报表  
    
钻取报表是通过设置Navigation(HyperLink)Parameters来实现的,通常在OLAP应用程序中很有用。 
   4
、具有子报表的钻取报表
    
这个例子实现的功能类似Excel中数据透视表(Pivot Table)的功能,在一个复杂的交叉表中可以进行时间和商品两个维度的向下钻取。这在别的报表中恐怕是很难实现的。如图所示, 


   5
、引用外部代码块

   此示例演示从另外一个类Util中读取函数返回值到报表中:首先,使用LocalReportAddTrustedCodeModuleInCurrentAppDomain方法允许Util类中的方法在Report Viewer中执行,然后在报表中使用TextBox控件的Value节点调用Util中的静态方法Factorial在报表中显示其返回值。 
   
另外一个相关的示例基本上与此相同,只不过在Util类中访问一个文本文件并将该文本文件中的字符显示在报表中

   6、导出到Excel

   RDLC报表导出到Excel中的效果非常好,曾经看到另外一个报表设计器(好像就是Crystal Report)导出为Excel文件后的效果非常差,单元格根本不对齐,用户无法在其基础上进行二次操作,而RDLC报表导出的Excel文件就没有这个缺点,而且基本上完全保留了原报表设置的格式。如图所示,

    可以直接使用Report Viewer控件自带的按钮生成Excel文件,也可以使用如下代码来完成操作:

Microsot.Reporting.WinForms.Warning[] Warnings; 
string[] strStreamIds; 
string strMimeType; 
string strEncoding; 
string strFileNameExtension;

byte[] bytes = this.rptViewer.LocalReport.Render("Excel", nullout strMimeType, out strEncoding, out strFileNameExtension, out strStreamIds, out Warnings);

string strFilePath = @"D:/report.xls";

using (System.IO.FileStream fs = new FileStream(strFilePath, FileMode.Create)) 

fs.Write(bytes, 0, bytes.Length); 
}

   对于LocalReportRender方法,以后的随笔中将进行详细阐述。
   7
、交互排序

   RDLC报表的众多交互功能中,这个功能是比较新颖的,终端用户可以通过报表中列标题上的图标进行数据的排序,而预览及打印的效果完全取决于用户的排序。[此处好像有一个Bug,即对数据进行一种排序后的预览效果会保持不变,除非再次开启这个应用程序并重新排序。]而这一切不需要在代码中做任何操作,只需要在报表定义文件中添加<UserSort>节并指定相应的SortExpressionSortExpressionScope

   8RSS新闻阅读器

   ReportViewer实现RSS新闻阅读器?是的!如图所示,

   当然这个sample是为了展示对Object类型数据源的支持,报表参数ReportParameter的使用也在其中得到体现。

    9、允许钻取的主子表

    另外一种允许向下钻取的主子报表。如图所示,

   10、从命令行中打印报表

   RDLC报表允许用户不通过ReportViewer图形界面直接使用代码控制输出和打印,还是使用LocalReportRender方法,以后的随笔中将参照这个示例介绍一个如何自定义纸张的方法。

   11、票据生成

   这个示例允许用户输入一个单据及其明细后直接生成一个可供打印的票据。如图所示,

   12、动态生成一个RDLC文件

   这可能是一个最最重要的示例了,RDLC文件是用XML来描述的,可以直接使用代码生成之,这样的报表就可以非常灵活了。像网上比较流行的从DataGridView直接预览、打印数据的程序完全可以用这种方法来替代;进一步引申的话,完全可以实现一个自己的基于RDLC的报表设计器,这样可以让终端用户参与到报表的设计中,至少可以使他们能够修改报表中一些标题、表头等。

   GotReportViewer还提供了几个其他的例子,如设置报表参数、通过Email邮寄报表等,由于不是非常典型,不再赘述。

   GotReportViwer不知道为什么最近上不去了,有需要这些例程的朋友可以留下Email

   仔细想了一下,我觉得一篇step by step的随笔似乎是不必要的,由于RDLC报表设计时的简易性,任何有报表经验的人都可以在摸索后很容易就掌握其报表的设计方法。本来在这篇随笔中想谈一下对RDLC报表文件的解析,但是MISGoldPrinter的作者flygoldfish(长流支流)已经对这方面进行了详细的总结(见http://blog.csdn.net/flygoldfish/archive/2005/12/16/554035.aspx),长江支流对报表非常有研究,建议大家到他的Blog上看看,不过我觉得他实现的金质打印通完全可以用RDLC报表中的内容所替代,这只是个人意见,希望以后能见到他的更多作品。
    
另外,我手头有一份RDL规范(Report Definition Language Specification),非常值得阅读,推荐给大家http://files.cnblogs.com/waxdoll/RDLCS.rar。两幅截图:


Matrix


Table 

    偶然看到的一个关于RDL的评论:

        Microsoft   use RDL as the linch pin in its new Reporting Services. Even MS Managers admit that Reporting Services’ success is dependent on adoption of RDL by third party BI ISVs. But Microsoft   has consistently taken markets away from its BI partners and ISVs. Free Reporting Services is just the latest which starts with free OLAP Server, free Analytical/Data Mining Services, and a rash of free client side OLAP to Office 2003 utilities and templates. 

Now Microsoft  will argue that its just expanding the BI markets. ISV and BI vendors will have to decide if they want to help Microsoft  “expand the BI markets”. So far Cognos has said it will support RDL at some time in the future; while Business Objects/Crystal says it is considering RDL. Curiously, except for Computerworld, the XML and BI community of publications have been virtually silent about RDL - neither its virtues/weaknesses nor the dilemma it poses to Microsoft’s “BI partners” have made the usually boisterous trade press. 

        RDLC报表中有一个概念叫数据区域(Data Region),数据区域是数据绑定的报表项目,在数据区域中可以显示来自数据集的多行数据。RDLC报表设计器中的数据区域包含控件面板上的一系列控件:ListTableMatrixChart,如图所示,

        List控件的用处在于这是一个在其中可以自由安排像TextBoxImage等控件;Chart控件用于显示图表,和Excel中的图表比较相似。这篇随笔不会涉及到这两个控件,主要讲一下TableMatrix两个控件。

        先来看Table控件。Table控件有多个部分组成,如标题行(header)、表尾(footer)、数据行(detailed rows)、分组表头(group header)、分组表尾(group footer)等,如图所示,

        之所以设计这样一个控件,我想Microsoft一定是在简化报表的设计:

        在这个控件未出现之前,我们看一下一个具有heaerdetailed rows和带统计信息的footer的报表时如何实现的。首先,这个报表需要显示报表页眉、主体和报表页脚三个部分,然后在报表页眉中拖曳进一系列Label形成表格的标题行,接着在主体部分拖曳进一系列TextBox用于显示数据行,并在报表页脚中拖曳进一系列LabelTextBox用于显示统计信息;要命的是,这些LabelTextBox需要在某个方向上进行对齐,控件宽度的调节也非常麻烦,如果需要显示表格线,那么没办法,需要使用Line控件手工画,这是非常麻烦的一件差事,相信没人会喜欢用这么麻烦的方法来设计这么一个简单的报表。

        现在,Microsoft推出了Table控件,你需要做的只是确定表格的列数(因为表格的列数需要是固定的),然后将字段从Data Sources面板中拖曳到Table控件的数据行中就可以了,报表设计器会自动为你生成标题行中的标题信息;至于footer中的统计信息Microsoft甚至为我们设计了一个表达式生成器,使用起来非常简便;列宽可以通过拖曳来调整,表格线可以通过设置Table控件的属性来完成。

        是的,一切就是这么简单!这也很可能是为什么你在Visual Studio 2005的报表设计器中找不到报表页眉和报表页脚的原因,只有页面页眉(page header)和页面页脚(page footer)就足够了!

        当然,可能报表中也需要不是像表格这么整齐排列的数据区域,这时候就需要用到List控件了。

        在实际应用中,发现一个表格控件可以具有零个、一个或多个headerfooter,甚至可以没有detailed rows,这样的表格控件有什么作用呢?我们知道detailed rows是用来显示多行数据的,而heaerfooter都可以用来显示sumcount等统计信息。假如我们的数据集中同时具有主子表(如通过Inner Join获得的一个查询)的信息,而这时候我们需要将主报表的信息单独显示出来使整个报表形成一个主子表的样式,那么我们就可以用到没有detailed rowsTable控件了,为headerfooter中的单元格指定First(Fields!字段名称.Value, "数据源名称")就可以了,这样至少减少了我们排列这些字段信息的烦恼。也就是说,Table控件是非常灵活的。CodeProject上有一篇文章One to Many Reports with VS.NET 2005 (2.0) Report Designer(http://www.codeproject.com/dotnet/1tomanyreports_vsnet2005.asp)即是用这种主子数据集显示的主子报表,但是个人觉得不如上面描述的方法来的简单,顶多给报表增加一个可以标识主记录的参数而已。当然,正儿八经的主子报表还是需要借助SubReport控件来实现。

        再来看一下Matrix控件,这个控件可以看作是Microsoft的又一个创新,以前的报表中可能会有交叉表(crosstab),但Matrix控件反映的不只是一个交叉表,还可以看作是一个带钻取功能的数据透视表(pivot table)Matrix控件由以下部分组成:

 

        如果由我们自己使用一个普通的数据集来绘制一个crosstab,那会是一个非常麻烦的工作,我们需要:为数据透视报表设置行标题;计算可能的列标题数量并设置列标题,根据行标题和列标题在数据集中循环查询由当前行标题和列标题决定的值,整个过程的计算量就够受的了。作为被Microsoft封装过的一个控件,Matrix控件显然不需要这么麻烦,简单的拖曳操作并设置其属性就可以了。当然,在报表中使用交叉表最重要的一点是最终显示的结果必须是有意义的。

        需要注意的是,当包含Matrix控件的报表导出到Excel文件中以后,即使是未显示的带有钻取标志的区域也将被显示出来,可能你会有这样的疑问:既然是数据透视表,为什么在Excel中不能显示成折叠的样式呢?这是因为报表的导出功能是并不依赖于Excel的。 


       
随着Visual Studio 2005中文版的推出,Microsoft汉化了MSDN的大部分内容,开发者再也不用啃英文了,本来想介绍一下LocalReportRender方法,现在您可以到http://msdn2.microsoft.com/zh-cn/library/ms252207(VS.80).aspx获得关于这部分的详细信息。之所以以前想介绍这个方法,是因为我将想大家介绍一种在Crystal Report中无法实现的自定义票据打印纸张的方法。Anyway,现在我直接向大家介绍这种方法,可能这种方法并不是很好的,但是确实是我经过一段时间的摸索总结出来的。萝卜(http://luobos.cnblogs.com)曾经提到过的变通的方法不知道是不是我要介绍的这一种,欢迎和我进行交流!

        要想使用RDLC报表并进行页面设置,我们先来看一下LocalReport是否有类似PageSettings的类、属性、方法或事件等,我仔细找了一下,发现Microsoft.Reporting.WinForms.ReportPageSettings类具有PaperSize属性和Margin属性,但可惜的是它们都是只读的,对我们来说没有意义;另外,LocalReport具有GetDefaultPageSettings()方法,这也只能是获取当前报表的页面设置。没办法,只能采用变通的方法了。在.NET中如果想使用自定义纸张,最好的方法莫过于使用System.Drawing.Printing.PrintDocument类了,还记得我在前面提到的一个GotReportViewer的例子吗?

    private int m_currentPageIndex;
    
private IList<Stream> m_streams;

    
private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
    
{
        Stream stream = 
new FileStream(name + "." + fileNameExtension, FileMode.Create);
        m_streams.Add(stream);
        
return stream;
    }

    
private void Export(LocalReport report)
    
{
        
string deviceInfo =
          "<DeviceInfo>" +
          "  <OutputFormat>EMF</OutputFormat>" + 
          "  <PageWidth>8.5in</PageWidth>" +
          "  <PageHeight>11in</PageHeight>" +
          "  <MarginTop>0.25in</MarginTop>" +
          "  <MarginLeft>0.25in</MarginLeft>" +
          "  <MarginRight>0.25in</MarginRight>" +
          "  <MarginBottom>0.25in</MarginBottom>" +
          "</DeviceInfo>";
        Warning[] warnings;
        m_streams = 
new List<Stream>();
        report.Render("Image", deviceInfo, CreateStream, 
out warnings);

        
foreach (Stream stream in m_streams)
            stream.Position = 0;
    }

    
private void PrintPage(object sender, PrintPageEventArgs ev)
    
{
        Metafile pageImage = 
new Metafile(m_streams[m_currentPageIndex]);
        ev.Graphics.DrawImage(pageImage, ev.PageBounds);

        m_currentPageIndex++;
        ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
    }

    
private void Print()
    
{
        
const string printerName = "Microsoft Office Document Image Writer";

        
if (m_streams == null || m_streams.Count == 0)
            
return;

        PrintDocument printDoc = 
new PrintDocument(); 
        printDoc.PrinterSettings.PrinterName = printerName;
        
if (!printDoc.PrinterSettings.IsValid)
        
{
            
string msg = String.Format("Can't find printer /" {0}/".", printerName);
            Console.WriteLine(msg);
            
return;
        }
        printDoc.PrintPage += 
new PrintPageEventHandler(PrintPage);
        printDoc.Print();
    }

    
private void Run()
    
{
        LocalReport report = 
new LocalReport();
        report.ReportPath = "Report.rdlc";
        report.DataSources.Add(
new ReportDataSource("Sales", LoadSalesData()));

        Export(report);

        m_currentPageIndex = 0;
        Print();
    }

        对,就是那个通过命令行而不是ReportViewerGUI界面进行打印报表的例子,这个例子就使用LocalReportRender方法将报表的内容导出为EMF图像流,然后在PrintDocumentPrintPage事件中使用时事件参数System.Drawing.Printing.PrintEventArgs类的DrawImage方法将EMF图像流输出到打印机。我在上面说的变通的方法也要使用这种方法。具体的细节将在以后的随笔中陆续给出。

        既然我们使用这种方法进行报表的打印,那么Visual Studio的控件ReportViewer的工具栏就不再符合我们的要求了。因为这个报表浏览器的工具栏上的按钮虽然可以设置属性显示或隐藏其中的一部分,但是我们却不能自己往这个工具栏上添加按钮(显然,我们需要实现自己的页面设置、预览和打印按钮),在这一点上,建议Microsoft将工具栏和报表浏览器分离,应该做得和BindingNavigator那样就好了。

        我们先设置ReportViewer控件的ShowToolBar方法为false,然后在ReportViewer控件纸上添加除页面设置、预览、打印外的应该有的按钮,像刷新、终止、导出、缩放、搜索、导航等,这些按钮的Click事件定义如下:

        /**//// <summary>
        
/// 
获取当前时间组成的字符串,用作生成不会重复的文件名
        
/// </summary>
        
/// <returns></returns>
        private string GetTimeStamp()
        
{
            
string strRet = string.Empty;
            System.DateTime dtNow = Pub.DateTimeEx.ServerTime;
            strRet +=   dtNow.Year.ToString() +
                        dtNow.Month.ToString("00") +
                        dtNow.Day.ToString("00") +
                        dtNow.Hour.ToString("00") +
                        dtNow.Minute.ToString("00") +
                        dtNow.Second.ToString("00") +
                        System.DateTime.Now.Millisecond.ToString("000");
            
return strRet;

        }

        
/**//// <summary>
        
/// 
导出到Excel
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void toolExcel_Click(object sender, EventArgs e)
        
{

            Microsoft.Reporting.WinForms.Warning[] Warnings;
            
string[] strStreamIds;
            
string strMimeType;
            
string strEncoding;
            
string strFileNameExtension;

            
byte[] bytes = this.rptViewer.LocalReport.Render("Excel", nullout strMimeType, out strEncoding, out strFileNameExtension, out strStreamIds, out Warnings);

            
string strFilePath = @"D:/" + this.GetTimeStamp() + ".xls";

            
using (System.IO.FileStream fs = new FileStream(strFilePath, FileMode.Create))
            
{
                fs.Write(bytes, 0, bytes.Length);
            }

            
if (Pub.WinForm.Msg.Question("
报表打印: /r/n    成功导出Excel文件!" + strFilePath + "/r/n    要现在打开文件" + strFilePath + "吗?") == DialogResult.Yes)
            
{
                System.Diagnostics.Process.Start(strFilePath);
            }

        }

        
/**//// <summary>
        
/// 刷新报表数据
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
刷新_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.RefreshReport();
        }

        
/**//// <summary>
        
/// 在加载报表数据时终止报表数据的加载
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
终止_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.CancelRendering(0);
        }

        
/**//// <summary>
        
/// DrillThrough报表返回到导航页面
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
返回_Click(object sender, EventArgs e)
        
{
            
if (this.rptViewer.LocalReport.IsDrillthroughReport)
                
this.rptViewer.PerformBack();
        }

        
/**//// <summary>
        
/// 回到报表的第一页
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
第一页_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.CurrentPage = 1;
        }

        
/**//// <summary>
        
/// 跳转到报表的最后一页
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
最后一页_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.CurrentPage = this.rptViewer.LocalReport.GetTotalPages();
        }

        
/**//// <summary>
        
/// 25%的比例显示报表
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool25_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.Percent;
            
this.rptViewer.ZoomPercent = 25;
        }

        
/**//// <summary>
        
/// 
50%的比例显示报表
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool50_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.Percent;
            
this.rptViewer.ZoomPercent = 50;
        }

        
/**//// <summary>
        
/// 
100%的比例显示报表
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool100_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.Percent;
            
this.rptViewer.ZoomPercent = 100;
        }

        
/**//// <summary>
        
/// 
200%的比例显示报表
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool200_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.Percent;
            
this.rptViewer.ZoomPercent = 200;
        }

        
/**//// <summary>
        
/// 
400%的比例显示报表
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool400_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.Percent;
            
this.rptViewer.ZoomPercent = 400;
        }

        
/**//// <summary>
        
/// 
将缩放模式设置为整页
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
整页_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.FullPage;
        }

        
/**//// <summary>
        
/// 将缩放模式设置为页宽
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
页宽_Click(object sender, EventArgs e)
        
{
            
this.rptViewer.ZoomMode = ZoomMode.PageWidth;
        }

        
/**//// <summary>
        
/// 在报表中搜索txtSearch中的字符
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
搜索_Click(object sender, EventArgs e)
        
{
            
if (this.txtSearch.Text.Trim() == string.Empty)
                
return;

            
this.rptViewer.Find(this.txtSearch.Text.Trim(), 1);
        }

        
/**//// <summary>
        
/// 搜索报表中下一处txtSearch中的字符
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
搜索下一个_Click(object sender, EventArgs e)
        
{
            
if (this.txtSearch.Text.Trim() == string.Empty)
                
return;

            
this.rptViewer.FindNext();
        }

        
/**//// <summary>
        
/// 跳转到上一页
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
上一页_Click(object sender, EventArgs e)
        
{
            
if (this.rptViewer.CurrentPage != 1)
                
this.rptViewer.CurrentPage--;
        }

        
/**//// <summary>
        
/// 跳转到下一页
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
下一页_Click(object sender, EventArgs e)
        
{
            
if (this.rptViewer.CurrentPage != this.rptViewer.LocalReport.GetTotalPages())
                
this.rptViewer.CurrentPage++;
        }

        
/**//// <summary>
        
/// 跳转到由txt跳转中指定的页数
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void tool
跳转_Click(object sender, EventArgs e)
        
{
            
if (this.txt跳转.Text.Trim() == string.Empty)
                
return;

            
int intJump = 0;

            
if (System.Int32.TryParse(this.txt跳转.Text.Trim(), out intJump))
                
if (intJump <= this.rptViewer.LocalReport.GetTotalPages())
                    
this.rptViewer.CurrentPage = intJump;

        }