65.9K
CodeProject 正在变化。 阅读更多。
Home

应用 MS Reporting Services 101(使用智能客户端)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (26投票s)

2006年8月24日

14分钟阅读

viewsIcon

141037

downloadIcon

1174

使用智能客户端主机开始使用 MS Reporting Services 的应用方法

Sample Image - rsimage1.jpg

图 1

引言

我还记得那是一个做得非常棒的报表,它为我赢得了第一次加薪(每个人都喜欢加薪,对吧?)。从那时起,我对报表编写就充满了热情。在这篇文章中,我将一步一步地指导您如何使用 MS Reporting Services 2005 创建一个简单的报表;并将其托管在 Smart Client 应用程序中。

那么,您准备好分享加薪的喜悦了吗?为什么不呢!谁知道呢,您精心制作的报表或许就能带来这样的结果。

在这篇文章之前,我写了另外三篇,它们解决了与报表服务相关的不同问题。然而,它们都面向中高级读者。根据我收到的所有反馈,有一个普遍的请求:很多人希望有一篇专门针对初学者级别的文章。

我假设读者对 Visual Studio 2005 IDE 有基本的了解,并且熟悉使用 C# 编写代码。您不必了解 MS Reporting Services 即可理解本文;尽管如此,任何以前的报表编写经验都有助于您更快地掌握。

虽然我称这篇文章为 101,但我的意图是采用实践方法,而不是讨论报表服务相关的每一个话题。我将重点介绍最常见的报表设计方面以及最常用的控件。我强烈建议您查阅 MSDN 文档以获取更详细的信息。

*已更新,添加了 Access 数据库接口。

撸起袖子,开始报表制作

请看 图 1。这个报表有多复杂?您觉得创建这样的报表需要多长时间?嗯,就复杂性而言,这是一个从源文件 NorthWind->Products (SQL Server 2000) 中提取出来的简单报表,列出了所有产品的详细信息以及汇总总计。

至于时间,显然,它不应该花费您几个小时。至于研发和试错时间,我留给您;深入探索,越深入您会发现越好的宝藏。

就是这样,价值百万美元的问题:如何开始?第一步是什么?

通常,找出第一步是什么很容易。您见过在没有地基的情况下建造房屋吗?没有!那么,我在这里给您提示了吗?当然,我们必须先开发 Smart Client 来托管我们的报表。

步骤 1:创建 Windows 应用程序项目

请执行以下操作来创建 Windows 应用程序(Smart Client)项目

  • 选择 文件菜单 -> 新建 -> 项目
  • 项目类型窗格 中选择 C#。
  • 模板窗格 中,为 Visual C# 项目选择 Windows 应用程序

在“名称”框中,为项目命名一个唯一的名称(我为附加的项目代码命名为 - rsWin101),以表明应用程序的用途。在“位置”框中,输入要保存项目的目录,或单击“浏览”按钮进行导航。完成后,您会发现 Form1 已添加到项目中,您可以使用 Forms Designer 开始对其进行操作。

请更新 Form1 的以下属性

Form1.Text = “MS Reporting Services 101 with Smart Client”
Form1.Size = 750, 300

您可以根据需要自由更改 Form1 的任何其他属性。

步骤 2:将 Report Viewer 添加到窗体

那么,什么是报表查看器?就像我们需要 DVD 播放器来播放 DVD 一样;报表也一样,我们需要一个报表查看器来预览报表。

对于所有刚接触报表编写的人,我想说,报表查看器赋予了您的报表生命。它不仅可以预览输出,还可以帮助您以各种流行格式(pdf、Excel 等)生成信息。您还可以打印出正在查看的报表的硬拷贝。

请执行以下操作,将 Report Viewer 控件设置到 Form1

  • 从工具箱拖动 工具箱 -> 数据 -> ReportViewer 并将其拖放到 Form1 上。此步骤将创建一个名为 reportViewer1 的新 ReportViewer 实例。我一直想将 reportViewer1 重命名为 rpvAbraKaDabra,所以现在不能错过这个机会。既然我选择了 rpvAbraKaDabra,您也可以随意选择您喜欢的名字,让想象力尽情驰骋!
  • 通过设置 reportViewer1.Dock = Fill,报表查看器将填充窗体的整个表面用于报表显示。

完成步骤 1 和步骤 2 后,您的项目应该如 图 2 所示。

Sample screenshot

图 2

步骤 3:将 DataSet 添加到项目

万岁!我们已经完成了基础。现在是时候为地基砌墙了;最终这些墙将支撑您家的门窗。DataSet 对 Report Viewer 来说就像是这样,它存储并提供来自数据源的原始数据,以便进行处理并准备在 Smart Client 界面上输出。

需要执行以下步骤将 DataSet 添加到项目

  • 从“解决方案资源管理器”选择 添加 -> 新建项 -> DataSet。将名称从 DataSet1 更改为 dsProduct,然后单击“添加”按钮完成操作。

让我们向新创建的 DataSet 添加一个 DataTableDataTable 对于加载报表数据至关重要;我们在设计报表时将使用 DataSet/DataTable 中的信息。

需要执行以下步骤将 DataTable 添加到 DataSet(dsProduct)

  • 双击“解决方案资源管理器”中的 dsProduct;它将打开设计器视图。右键单击设计器表面,选择 添加 -> DataTable 请单击标题并将其名称更改为 dtProductList。请参见 图 3

Sample screenshot

图 3

让我们开始为 DataTable(dtProductList) 添加列。您的设计器屏幕应如 图 4 所示。右键单击 dtProductList 并选择 添加 -> 列 以开始向 DataTable 添加列。

Sample screenshot

图 4

请为以下列重复此操作

  • ProductName (字符串)
  • QuantityPerUnit (字符串)
  • UnitPrice (双精度)
  • UnitsInStock (双精度)
  • UnitValue (Double) – 基于 UnitsInStock * UnitPrice 的计算字段

当您添加列时,默认数据类型是 string。请选择列后转到属性窗口,将其从 String 更改为 IntegerDouble

请参见 图 5。您的 DataTable 应与此相同。您也可以查看属性窗口来更改数据类型。

Sample screenshot

图 5

您听说过“强类型 DataSet”吗?如果没有,那么我们刚刚在这里创建了一个强类型 DataSet。请查阅在线帮助以了解更多关于强类型 DataSet 的信息。

步骤 4:将报表添加到项目

好的,到目前为止我们已经创建了项目;添加了 Report Viewer 和 DataSet。现在,是时候处理这场演出的明星了!让我们创建那个漂亮的报表。

需要执行以下步骤来创建 Report (rptProductList.rdlc)

  • 从“解决方案资源管理器”选择 添加 -> 新建项 -> 报表。将名称从 Report1.rdlc 更改为 rptProductList.rdlc,然后单击“添加”按钮完成操作。

通常,添加操作完成后,您的屏幕应与 图 6 类似。当报表添加到项目中时,它就可以使用 DataSet 进行设计了。

Sample screenshot

图 6

无论这是您的第一个报表,还是您像我一样是个报表爱好者;我们都必须处理报表编写最基本的构建块,即:页眉、正文和页脚。

通常,报表的设计会考虑特定的页面大小和布局。我们的报表是 Letter 尺寸和纵向布局。您可以通过右键单击打开的设计器表面的任意位置并选择“属性”来探索报表布局的各种属性。

在开始设计尝试之前,始终建议在纸上绘制报表的原型。如您在 图 1 中所见,我们在页眉部分有报表名称和报表日期。正文部分包含产品列表信息以及汇总总计;页脚包含页码。

让我们开始处理页面页眉

当新报表添加到项目时,默认情况下,您在报表设计器中看到的只有正文部分。右键单击报表设计器表面的正文以外的任何位置,然后选择 Page Header。这将在报表中添加页眉。请随意调整页眉和正文部分的高度。请参见 图 7,我已减小了正文的高度并增加了页眉的高度。

Sample screenshot

图 7

在报表设计器中,如果您查看工具箱,会看到各种可用于设计报表的控件。在本例中,我们将使用 TextBoxLineTable 控件。如果您需要有关所有可用控件的详细信息,我鼓励您查阅在线文档。

页眉部分

让我们开始设计页眉。我们将通过将两个 TextBox 控件拖放到页眉部分开始。Textbox 可以显示静态和动态数据。Line 控件用于将页眉与正文部分分隔开。

在报表设计器表面放置控件后,您可以通过更改关联属性来控制外观。我们将指定一个 TextBox 用于报表标题,另一个用于显示当前日期。您可以通过选择 TextBox 控件并直接在其中键入来输入静态文本。

请更改标题 TextBox 的以下属性

Value = “Product List”
Color = Purple (you like purple too for title right?)

请更改日期 TextBox 的以下属性

Value = ="Run Data: " & Today
Color = Purple (you like purple too for title right?)

请注意,日期 TextBoxValue 属性以“=”符号开头。这不是简单的静态文本,而是表达式。此表达式是字符串“Run Date”和 VB.NET 脚本 关键字 Today(用于获取当前系统日期)的结果。

您可以为报表中的所有对象指定所需的名称;我选择保留大多数控件的默认名称,但为了演示目的,我为标题 TextBox 指定了“txtTitle”。

请参考 图 8;您完成的页眉设计应大致相同。

Sample screenshot

图 8

正文部分

正文部分,也称为详细信息部分,是报表中最重要的部分。如您所见,当我们向项目中添加报表时;正文部分会自动为我们添加。我们只需开始在其上放置控件。

传统上,正文部分用于显示详细信息(在本例中是产品信息),通常是一行以上的信息。正文部分可以根据报表数据的增长而扩展。通常报表设计时会考虑输出一个物理页面(Letter/A4 等);在这种情况下,正文部分仍然可以用于显示信息。

TableMatrixList 这三个正文部分最常用的控件中;我们将为我们的示例使用 Table 控件。这三者都可以重复信息;Matrix 更进一步,甚至可以生成透视输出。

让我们将 Table 控件拖放到报表设计器表面的正文部分。如果您注意到,此操作将生成一个具有三行三列的表。您可能还注意到中间列也已标记:HeaderDetailFooter

现在,如果我告诉您 Table 控件只不过是一堆 TextBox 组合在一起!您不必感到惊讶。是的,Table 中的每一个单元格都像 TextBox,这意味着您可以键入静态文本,也可以指定动态表达式。

在我们开始设计正文部分之前,让我们再添加两列(记住报表总共有五列)。添加列很容易;请执行以下操作以将新列添加到报表中

  • 在正文部分选择 Table 控件
  • 单击最右侧的列标题(我假设我们在右侧添加新列)
  • 右键单击标题并选择 -> 在右侧插入列

请确保您的报表看起来像 图 9。您可以根据将要保存的数据长度自由调整列宽。

Sample screenshot

图 9

我敢肯定我们中的大多数人都使用过 Excel 或类似工具;可以将 Table 控件想象成迷你工作表。我们可以应用边框,更改单个单元格的字体等。所以,您所要做的就是构思所需的格式主题并开始应用。

从第一列到最后一列,请单击单个列标题单元格并键入以下文本

Header 1: “Product Name”
Header 2: “Packaging”
Header 3: “Unit Price”
Header 4: “Units in Stock”
Header 5: “Stock Value”

让我们继续为 Detail 部分做同样的事情,这里需要知道的是,我们必须键入的不是文本,而是来自 dsProduct.dtProductInfo 的列表达式。您可以键入表达式,也可以简单地将列从“数据源”工具栏(参见左侧的 图 7)拖放。

如果您选择键入,从第一列到最后一列,请单击单个列详细信息单元格并键入以下文本

Detail 1: “=Fields!ProductName.Value”
Detail 2: “=Fields!QuantityPerUnit.Value”
Detail 3: “=Fields!UnitsInStock.Value”
Detail 4: “=Fields!UnitPrice.Value”
Detail 5: “=Fields!UnitsInStock.Value * Fields!UnitPrice.Value”

请注意详细信息 5:这是通过将 Units in Stock 和 Unit Value 相乘计算出的结果。

提示:如果您将列拖放到 Table 控件的详细信息部分,它会尝试自动添加列标题,如果列标题为空。

最后,让我们在 Table 控件的页脚部分添加汇总总计。请确保在 Body 部分内的第 4 列和第 5 列的页脚单元格中键入以下文本

Cell 4: “Total Value:”
Cell 5: “=SUM(Fields!UnitsInStock.Value * Fields!UnitPrice.Value)”

请检查第 5 列中的表达式;我正在使用内置函数 SUM() 来计算报表中列出的所有产品的总库存价值。

页脚部分

在我们开始编写一些酷炫的 C# 代码使报表栩栩如生之前,让我们完成报表页脚部分。正如我们之前添加了报表页眉一样,我们必须右键单击打开的报表设计器表面并选择 Page Footer(参见 图 7)。

LineTextBox 控件拖放到 Footer 部分。请在 TextBox 中键入以下表达式

Value:  ="Page: " & Globals!PageNumber & "/" & Globals!TotalPages

正如您所见,我使用了 PageNumberTotalPages,它们都是报表引擎维护的全局变量。

提示:请确保您键入的所有表达式都以“=”开头。

请确保您的报表看起来像 图 10。正如您所见,我已经引入了一些颜色和右对齐数字数据等。请随意尝试所有不同的格式选项,只需将 Table 控件视为具有列和行的迷你电子表格,您就知道可以对其进行所有格式设置了。

Sample screenshot

图 10

表达式生成器

表达式生成器是 Reporting Services 的一个非常强大的功能。正如您在 图 11 中所看到的,Stock Value 是借助 SUM 函数计算的。DataSet 中的所有字段都可以通过“Fields!”关键字访问。

Sample screenshot

图 11

步骤 5:编写一些 C# 代码,让报表活起来

呼……希望你们还没有感到疲惫。坚持住;我们现在在最后一步了。就像我们等待了九个月,终于迎来了生命的奇迹。

从解决方案资源管理器中,选择 Form1。右键单击窗体表面并选择“查看代码”。

using System.Data.SqlClient;
using Microsoft.Reporting.WinForms;

请确保 Form1_Load 事件具有以下代码

private void Form1_Load(object sender, EventArgs e)
{
    //declare connection string
    string cnString = @"(local); Initial Catalog=northwind;" +
        "User Id=northwind;Password=northwind";

    //use following if you use standard security
    //string cnString = @"Data Source=(local);Initial 
    //Catalog=northwind; Integrated Security=SSPI";
 
    //declare Connection, command and other related objects
    SqlConnection conReport = new SqlConnection(cnString);
    SqlCommand cmdReport = new SqlCommand();
    SqlDataReader drReport;
    DataSet dsReport = new dsProduct();

    try
    {
        //open connection
        conReport.Open();

        //prepare connection object to get the data through reader and
        populate into dataset

        cmdReport.CommandType = CommandType.Text;
        cmdReport.Connection = conReport;
        cmdReport.CommandText = "Select TOP 5 * FROM
                  Products Order By ProductName";

        //read data from command object
        drReport = cmdReport.ExecuteReader();

        //new cool thing with ADO.NET... load data directly from reader
          to dataset

        dsReport.Tables[0].Load(drReport);

        //close reader and connection
        drReport.Close();
        conReport.Close();

        //provide local report information to viewer
        rpvAbraKaDabra.LocalReport.ReportEmbeddedResource = 
        "rsWin101.rptProductList.rdlc";

        //prepare report data source
        ReportDataSource rds = new ReportDataSource();
        rds.Name = "dsProduct_dtProductList";
        rds.Value = dsReport.Tables[0];
        rpvAbraKaDabra.LocalReport.DataSources.Add(rds);

        //load report viewer
        rpvAbraKaDabra.RefreshReport();
    }
    catch (Exception ex)
    {
        //display generic error message back to user
        MessageBox.Show(ex.Message);
    }
    finally
    {
        //check if connection is still open then attempt to close it
        if (conReport.State == ConnectionState.Open)
        {
            conReport.Close();
        }
    }
}

您可能想知道为什么我在 select 查询中使用了“TOP 5”;原因是我想限制输出,以便向您展示 图 1 中的汇总总计。

提示ReportDataSource 对象的 Name 属性应始终为“DataSet_DataTable”。

我可以使用 Access 而不是 SQL Server 2000 吗?

是的,您可以使用 Access 数据库。请确保在上述代码中应用以下更改,以便从 NorthWind Access Database 报告数据。

尽管 Northwind 数据库 随 Access 数据库安装一起提供;如果您没有它,可以在此处下载。

修改后的代码应如下所示

using System.Data.OleDb;

private void Form1_Load(object sender, EventArgs e)
{
    //declare connection string
    string cnString = @"Provider=Microsoft.Jet.OLEDB.4.0;
      Data Source=c:\nwind.mdb;User Id=admin;Password=;";

    //declare Connection, command and other related objects
    OleDbConnection conReport = new OleDbConnection(cnString);
    OleDbCommand cmdReport = new OleDbCommand();
    OleDbDataReader drReport;
    DataSet dsReport = new dsProduct();

    try
    {
        //open connection
        conReport.Open();

        //prepare connection object to get the data through
          reader and populate into dataset
        cmdReport.CommandType = CommandType.Text;
        cmdReport.Connection = conReport;
        cmdReport.CommandText = "Select TOP 5 * FROM
                       Products Order By ProductName";

        //read data from command object
        drReport = cmdReport.ExecuteReader();

        //new cool thing with ADO.NET... load data directly
          from reader to dataset
        dsReport.Tables[0].Load(drReport);

        //close reader and connection
        drReport.Close();
        conReport.Close();

        //provide local report information to viewer
        rpvAbraKaDabra.LocalReport.ReportEmbeddedResource =
        "rsWin101.rptProductList.rdlc";

        //prepare report data source
        ReportDataSource rds = new ReportDataSource();
        rds.Name = "dsProduct_dtProductList";
        rds.Value = dsReport.Tables[0];
        rpvAbraKaDabra.LocalReport.DataSources.Add(rds);

        //load report viewer
        rpvAbraKaDabra.RefreshReport();
    }
    catch (Exception ex)
    {
        //display generic error message back to user
        MessageBox.Show(ex.Message);
    }

    finally
    {
        //check if connection is still open then attempt to close it
        if (conReport.State == ConnectionState.Open)
        {
            conReport.Close();
        }
    }
}

结论

虽然我已尽力使本文的语言尽可能简单;如果您需要任何进一步的澄清,请随时与我联系。我将自己视为一名初出茅庐的作者;我还有很多需要学习;正是像您这样的读者,一直帮助我改进我的写作。

我期待收到您对我的任何评论/建议。

感谢您的阅读;我真诚地希望本文能通过我的实践方法,帮助您更好地了解报表服务。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.