技术开发 频道

ASP.NET下基于水晶报表编程的分组报表

  【IT168 专稿】在本系列第一篇中,我们给出了示例网站的轮廓构建,并详细分析了创建到SQL Server 2008示例数据库AdventureWorks连接的具体步骤。在第二篇中,我们详细描述了如何使用现有的数据库连接数据创建Crystal Report报表的页眉。在本文(最后一篇)中,我们要进一步探讨如何创建更为重要和实用的具有一对多关联关系的分组数据报表。此外,我们还将详细讨论Crystal Report Viewer的使用方法。

  一、实现分组报表

  根据一般的要求,当显示报告时,对应于当前销售订单编号的所有的销售订单详细记录都应显示出来。要做到这一点,你可以创建基于SalesOrderNumber字段的组,然后在组页脚后添加一个分页符。当你把一个组添加到报表中时,水晶报表将自动添加一对组页眉和组页脚节。你可以进一步动态地调整它们的格式。

  对于我们的报告来说,我们要实现在组页脚后进行分页,以便在下一页上显示下一条发票,而且,我们要重置页码,以便您可以独立地打印出发票和独立地邮寄这些发票。

  请遵循如下步骤操作:

  (1)切换到主报告视图。右键单击报表中任何空白处,并从弹出式菜单中选择插入“Insert Group…”。

  (2)随后会出现“Insert Group”对话框。从下拉列表框中选择字段SalesOrderHeader.SalesOrderNumber,并单击按钮OK。

  图1  从“Insert Group”对话框中选择分组依据

  (3)你会注意到报表中新添加了两个节:Group Header #1和Group Footer #1。默认情况下,系统会把一个名字为“Group #1 Name”的特殊域添加至Group Header #1部分。这将显示您将根据分组的字段。在本报表中,我们不需要组名(Group Name),因为它对应于销售订单号(将在页眉处打印它)。因此,你可以移除这个字段—只需要选择此字段,然后按下Delete键。

  (4)另外,我们不需要显示Group Header #1,所以,我们可以压缩此节。方法是右键单击此节头部,然后在弹出菜单中选择“Suppress (No Drill-Down)”。

  (5)下一步是告诉水晶报表在页眉之后的位置处进行分页,并且重置页码。为此,右键单击“Group Footer #1”节标题,并从弹出式菜单中选择“Section Expert”。

  (6)勾选“New Page After”选项附近的“Reset Page Number After”选项,并单击“OK”按钮。如图2所示。

  图2  使用“Section Expert”对话框重置页码

  (7)接下来,我们要在报表中添加发票的具体记录项。报表中的details节正好用于显示相应于表格SalesOrderDetail中的每一条记录。从字段管理器下展开表格节点Product。把字段ProductNumber拖动到Details节中。注意,当你把一个字段添加到Details节中的时候,水晶报表自动在报表页眉处(Page Header Section)添加一个列标题字段。列标题是一个简单的文本对象,你可以编辑为一个更友好的名称。例如,我们可以把列标题更改为“产品编号”。

  (8)把Product.Name字段拖动到Details节中,把列标题更改为“产品名称”,并把此字段的宽度修改为4800。

  (9)把SalesOrderDetail.OrderQty字段拖动到Details节中,改变列标题为“订单数量”。

  (10)把SalesOrderDetail.UnitPrice字段拖动到Details节中,改变列标题为“Unit Price”。

  (11)把SalesOderDetail.UnitPriceDiscount字段拖动到Details节中,并把此字段的宽度修改为600,并且把列标题改变为“折扣”。

  (12)把SalesOrderDetail.LineTotal字段拖动到Details节中,并且把列标题改变为“行总计”。

  (13)下一步是使用一个矩形包围列标题和details节部分,为的是在报表中突出显示。右击报表并选择“Insert”—“Box”。拖动矩形框使之包围列标题和组脚注部分(Group Footer)。

图3  使用矩形框包围列标题和组脚注部分

  (14)现在预览报表,您应该看到出现了记录行数据,而且每一组数据为矩形所包围。

  最后一步是建立在组页脚节处计算总数。LineTotal域的总和应当等于为发票的分组合计数(即小计)。在表格SalesOrderHeader的记录中有一个名为subtotal的字段,但由于某些原因它并不等于明细记录的总和。为了解决这个问题,我们将创建自己的分类汇总报表。然后,我们将进一步添加运费和税这两部分数据来计算发票总额。

  (15)右键单击details节中的字段LineTotal,从弹出菜单中选择“Select”—“Insert”—“Summary…”。

  (16)要汇总的字段默认情况下应当为SalesOrderDetail.LineTotal,而且应当进行求和计算(Sum)。在汇总位置下拉列表框中选择“Group #1: SalesOrderHeader.SalesOrderNumber – A”。单击按钮“OK”退出。

图4  插入汇总字段

  (17)这将在脚注中位于LineTotal字段的下部自动添加summary字段。注意,你可以需要调整一个组脚注的高度,使之看起来更美观一些。

  (18)右键单击此字段并选择“Format Object”。单击选项卡“Font”把字形样式更改为Regular(常规)。再单击选项卡“Number”并勾选“Display Currency Symbol”选项。最后,单击“OK”按钮。

  (19)按住Ctrl键依次点选summary字段和LineTotal字段,设置相同的大小和右对齐。

  (20)右键单击summary字段的左侧,插入一个文本对象。将文本更改为“小计:”和右对齐,它充当summary字段的标签。

  (21)现在添加税字段。展开字段管理器中的数据库字段节点,展开SalesOrderHeader表。拖动Tax字段到位于LineTotal摘要字段下方的组页脚处。

  (22)右键单击Tax字段左侧,插入一个文本对象。将文本更改为“税:”和右对齐。

  (23)拖动SalesOrderHeader.Freight字段到Tax字段的下方。

  (24)右键单击运费字段左侧,插入一个文本对象。将文本更改为“运费:”和右对齐。

  (25)按住Ctrl键依次点选summary字段,tax字段和Freight字段,使它们都具有相同的大小和右侧对齐。

  (26)现在,你必须创造一个求发票总计的公式。右键单击字段管理器中的公式字段节点。从弹出式菜单中选择“New…”并输入名称InvoiceTotal。单击“Use Editor”按钮。

  (27)输入下面的公式。此公式的作用是示分类汇总,税收和运费数据三项的和。

  源码清单1

Sum ({SalesOrderDetail.LineTotal}, {SalesOrderHeader.SalesOrderNumber}) +
  {SalesOrderHeader.TaxAmt}
+ {SalesOrderHeader.Freight}

  (28)单击公式编辑器左上角的“Save and close”按钮。

  (29)拖动InvoiceTotal公式字段到运费(Freight)字段下面的组页脚处。使这个字段与字段同样的尺寸,最后使它们的右边缘对齐。

  (30)因为这是一个汇总字段,所以我们在这个字段的上面加一条单实线,在下面加一条双实线。为此,请右键点击InvoiceTotal字段,然后从弹出菜单中选择“Format Object”。

  (31)单击“Border”选项卡,并设置上边框线样式为单实线(Single),设置底线样式为双实线(Double),单击确定。

  (32)现在,在InvoiceTotal的左边插入一个标签。右键单击InvoiceTotal字段的左边并选择“Insert—Text Object”。将文本更改为“发票总计:”和右对齐方式。

  注意,在本文示例中,我们几乎没有使用到报表的页眉和页脚节,因此,你完全可以对之进行压缩。压缩方法很简单。例如要压缩报表的页眉,只需右键单击这些节,然后从弹出菜单中选择“Suppress (No Drill-Down)”即可。

  二、创建报表的页脚部分

  设计报表的最后一步是把页码添加到页脚节。为此,需遵循如下步骤:

  (1)右键单击页面页脚节(Page Footer)。然后,从弹出菜单中选择“Insert”—“Special Field”—“Page N of M”。

  (2)把相应字段投放到报表的页脚节处。

  (3)把字段的宽度调整为整个页面的宽度。

  (4)右键单击上面字段,然后从弹出菜单中选择“Format Object”,设置水平对齐方式为居中对齐。

  如果你此时预览报表,你应该注意到,在每次SaleOrderNumber变化时页码都被重置为1(如图5所示)。

图5  预览页码显示形式

  下面,我们来讨论如何在一张ASP.NET页面中集成水晶报表数据。

  三、观察报表运行效果

  至此,我们已经完成报表的创建。下面,我们将构建一个普通Web页面来显示此报表。为此,我将创建一个简单的页面,它能够让用户选择客户,然后能够预览相应于选定客户的任何发票信息。在本文示例中,我们直接使用示例网站AdventureWorksReports生成的默认页面Default.aspx。

  请按照如下步骤进行操作:

  (1)打开页面Default.aspx,从工具栏中展开“报表”选项卡,然后把其中的CrystalReportViewer控件拖动到页面中。

  此后,系统会自动添加如下内容:

  紧跟着Page指令后面添加如下的Register指令。

  源码清单2

<%@ Register assembly="CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral,
PublicKeyToken=692fbea5521e1304"
namespace="CrystalDecisions.Web" tagprefix="CR" %>

  这段代码可以允许你使用VS2008内置的Crystal Reports Viewer控件。

  (2)在默认的DIV标记间加入如下代码:

  源码清单3

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="5" DynamicLayout="true" AssociatedUpdatePanelID="UpdatePanel1">
    
<ProgressTemplate  >
        
<div style="position: absolute; top: 2px; right: 0; width: 100%; text-align: right;">
            
<img alt="loading" src='<%=Page.ResolveUrl("~/progress.gif") %>'/>
            
<span style="background-color: rgb(204, 68, 68);"> <span style="color: #ff0066"><span
                
style="background-color: #999999"><span style="font-size: 14pt"><strong>正在加载数据,请稍候...</strong>...</span></span></span>
            
</span>
        
</div>      
    
</ProgressTemplate>
</asp:UpdateProgress>    
<div>
    请选择客户:
<asp:DropDownList ID="ddlCustomer" runat="server">
    
</asp:DropDownList>
        
    
<asp:Button ID="btnPreview" runat="server" onclick="btnPreview_Click"
      Text
="预览" />
    
    
<br />
    
<br />

    
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    
<ContentTemplate>
        
<CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server" AutoDataBind="true" />
    
</ContentTemplate>
        
<Triggers>
            
<asp:AsyncPostBackTrigger ControlID="btnPreview" EventName="Click" />
        
</Triggers>
    
</asp:UpdatePanel>
</div>

  上面的代码将在事件触发后在页面中添加一个填充有客户列表的下拉列表框。其中,“预览”按钮将负责取得所有对应于选定客户的数据并绑定到报表中。其中涉及到其中的AJAX编程,因为这不是本示例的重点,故不再赘述。

  (3)在后台代码文件中加入如下using指令:

  源码清单4

using System.Data.SqlClient;
using System.Configuration;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;

  (4)在Page_Load事件函数中加入如下代码:

  源码清单5

if (!IsPostBack)
   {
      
//使用数据填充下拉列表框
      SqlConnection cn = new   SqlConnection(
        ConfigurationManager.ConnectionStrings[
"AdventureWorksConnectionString"].ConnectionString);
      cn.Open();

      SqlCommand cmd
= new SqlCommand("SELECT DISTINCT LastName + ', ' +
                                              FirstName AS Name,
                                              Person.Contact.ContactID
" +
                                        "FROM Sales.SalesOrderHeader " +
                                  
"INNER JOIN Person.Contact " +
                                          
"ON Sales.SalesOrderHeader.ContactID =
                                              Person.Contact.ContactID " +
                                    "ORDER BY LastName + ', ' + FirstName", cn);
      SqlDataReader dr
= cmd.ExecuteReader();

      ddlCustomer.DataSource
= dr;
      ddlCustomer.DataTextField
= "Name";
      ddlCustomer.DataValueField
= "ContactId";
      ddlCustomer.DataBind();

      CrystalReportViewer1.Visible
= false;
   }
  
else
   {
      
if (CrystalReportViewer1.Visible == true)
      {
        
//重新绑定报表
         BindReport();
      }
   }

  上面的代码将使用数据库中客户数据填充下拉列表框控件。为此,你必须在你的网站配置文件web.config中添加必要的数据库连接字符串。例如,在本文示例中,我加入了如下代码(你自己则需要根据具体情况进行调整):

  源码清单6

<connectionStrings>
        
<add name="AdventureWorksConnectionString" connectionString="Data Source=zxzcom;Initial Catalog=AdventureWorks;Integrated Security=True" providerName="System.Data.SqlClient"/>
    
</connectionStrings>

  (5)在“预览”按钮click事件函数中加入如下代码:

  源码清单7

protected void btnPreview_Click(object sender, EventArgs e)
{
    BindReport();
    CrystalReportViewer1.Visible
= true;
}

 

  这段代码调用了一个定制方法BindReport(),然后显示水晶报表视图控件(Crystal Report Viewer)。

  (6)现在,添加如下的定制方法:

  源码清单8

private void BindReport()
{
    ReportDocument report
= new ReportDocument();
    report.Load(Server.MapPath(
"Invoice.rpt"));

    SetTableLocation(report.Database.Tables);

    CrystalReportViewer1.ReportSource
= report;

    report.DataDefinition.RecordSelectionFormula
=
              
"{SalesOrderHeader.ContactID} = " + ddlCustomer.SelectedItem.Value;
}

private void SetTableLocation(Tables tables)
{
    ConnectionInfo connectionInfo
= new ConnectionInfo();

    connectionInfo.ServerName
= @"ZXZCOM";
    connectionInfo.DatabaseName
= "AdventureWorks";
    connectionInfo.IntegratedSecurity
=true ;

    
foreach (CrystalDecisions.CrystalReports.Engine.Table table in tables)
    {
        TableLogOnInfo tableLogOnInfo
= table.LogOnInfo;
        tableLogOnInfo.ConnectionInfo
= connectionInfo;
        table.ApplyLogOnInfo(tableLogOnInfo);
    }
}

 

  上面代码中的第一个方法创建了ReportDocument类的一个实例。这个实例对应于先前创建的报告,并允许您在运行时操纵它。接下来,SetTableLocation()方法负责设置报告中的每个表格的位置。在本例中,假设您已经使用Windows系统安全模式来管理SQL Server 2008数据库服务器安全性。此时,水晶报表视图控件的数据源被设置为上面的报告对象。下一行代码负责使用从下拉列表中选定的客户数据动态过滤显示报告。这仅需创建一个带有WHERE子句的SQL字符串语句。注意,当你引用一个字段时必须使用大括号{}把报表字段包围起来。

  现在,你就可以运行上面的项目。如果你从下拉列表中选择“Abel, Catherine”并按一下“预览”按钮,那么你应该会看到如图6所示的运行时快照。

图6  发票报表应用程序的运行时快照

  你可以使用页面顶部的导航按钮来自由浏览报表,特别注意观察它是如何进行分组显示的。

  四、总结

  水晶报表是一个极其强大的报表工具,可以进行导出Word、Excel和RTF等文件,还可以生成复杂、漂亮的图表,可以说是进行Web和Windows桌面开发必备的利器。

  本系列文章中,我们使用详细的步骤与实例展示了使用水晶报表创建一个主/从式数据库记录报表的全过程。其中,我们详细介绍了如何使用公式编辑器以及动态设置格式。最后,我们把报表文件输出到ASP.NET页面中。特别值得一提的是,这款软件是随同Visual Studio 2008一起免费发行的。

  另外,通过文中水晶报表的构建过程不难看出,水晶报表本身的使用是比较简单的,对于以前有过VFP、VB及其他桌面应用报表开发的读者尤其如此。而报表构建前期的数据连接过程便显得比较重要,特别是涉及到多张表格的情况下,正确地确立这些表格间的关联关系直接决定了后面报表设计的成败,应引起足够的重视。

下载文章内清晰版图片:http://download.itpub.net/html/2009/1013/2432200910131042507946.shtml

系列文章索引:

ASP.NET 3.5下基于Crystal Reports的报表编程

ASP.NET下基于水晶报表编程的创建报表页眉

ASP.NET下基于水晶报表编程的分组报表

 

0
相关文章