在运行时从 DataGridView 动态创建 RDLC 报告 [英] Create RDLC report dynamically at run-time from a DataGridView

查看:21
本文介绍了在运行时从 DataGridView 动态创建 RDLC 报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表单 AdvancedSearchForm 带有一个 DataGridView 控件 dgrData 和一个按钮 Report 在 C# Winform 中.单击按钮 Report 后,我希望带有 ReportView 控件的表单显示的列与 DataGridView 中的列具有相同的列标题.

带有 DataGridView 和按钮的表单

点击报告"按钮时的预期输出:

我的DatagridView (dgrData) 控件与

相关联

  1. SQL

<块引用>

Select Id, c_Name from Country"

  1. 连接字符串

<块引用>

server=localhost;User Id=root;password=root;Persist Security Info=True;database=country_state

为了在运行时将数据加载到网格,我准备了以下 DataAdapter:

DataAdapter dataAdapter = DataAdapter.Current;//我将 SQL 语句和表名传递给我的数据库,该数据库知道 LoadData 函数中的 ConnectionStringDataTable dt0 = dataAdapter.LoadData("select Id, c_Name from `country`", "country");如果 (dt0 != null) {dgrData.DataSource = dt0;}

是否可以调用包含默认 reportviewer 控件的子表单,该控件显示包含与 datagridview (dgrData) 对应的列以及动态数据的表格的报表运行时?

详细输出期望:

  1. 点击按钮后,目标表单上的报表查看器应该会
    与数据源中的值相关联数据网格视图.因此,ReportViewer 控件在用户点击报表之前不知道有关报表中数据的任何信息运行时的按钮.
  2. 我希望该解决方案不需要创建单独的 RDLC文件,因为它导致外部依赖,停止当前流并在报告文件设计器中创建一个报告文件,该文件可以对用户来说太过分了.
  3. 我对 RDLC 设计器和关联数据源一无所知(我是愿意学习(^_^),但我不能强求这个学习要求在我的团队中)并将数据绑定到报告.我将不胜感激有效的编码示例(如果您的帮助包含理论).
  4. 我知道 ReportViewer 已经存在很长时间了.希望数据网格和数据网格之间 1-1 数据映射的示例解决方案以后在 SO 上更容易找到 ReportViewer.

注意:请在评论中告诉我是否需要我方提供任何其他数据.为了显示当前的解决方案,我必须创建一个 RDLC 文件,我必须在设计时将连接字符串和 SQL 放在其中,我希望在我正在寻找的解决方案中避免这种情况.我希望找到一种解决方案,其中 RDLC 文件是通过一些模块化代码生成的,这些代码也可以用于其他解决方案,而不必为我拥有 DataGrids 的每个表单设计它.

解决方案

作为在运行时动态创建 RDLC 报告的选项,您可以使用

解决方法

ReportColumnDynamicReport.ttReportForm 添加到您的应用程序或什至在可重用库中一次就足够了,然后简单地使用 like上面的例子.按照以下步骤创建动态报告模板.

报表列模型

创建一个包含标题、表达式、颜色等属性的报表列模型.我们将使用它来添加要报告的列.

使用系统;使用 System.Drawing;公共类 ReportColumn{公共报表列(字符串名称){姓名 = 姓名;标题 = 姓名;类型 = typeof(System.String);宽度 = GetPixelFromInch(1);Expression = string.Format("=Fields!{0}.Value", name);HeaderBackColor = Color.LightGray;}公共字符串名称 { 获取;放;}公共字符串标题{获取;放;}公共类型类型{获取;放;}公共整数宽度{得到;放;}公共浮动 WidthInInch{得到 { 返回 GetInchFromPixel(Width);}}公共字符串表达式 { 获取;放;}公共颜色 HeaderBackColor { 获取;放;}公共字符串 HeaderBackColorInHtml{得到 { 返回 ColorTranslator.ToHtml(HeaderBackColor);}}私人 int GetPixelFromInch(浮动英寸){使用 (var g = Graphics.FromHwnd(IntPtr.Zero))返回 (int)(g.DpiY * 英寸);}私有浮点数 GetInchFromPixel(int pixel){使用 (var g = Graphics.FromHwnd(IntPtr.Zero))返回(浮动)像素/g.DpiY;}}

报告模板

向项目添加运行时模板(也称为预处理模板)并将其命名为 DynamicReport.tt 并将此内容复制到文件中:

<#@ 模板语言=C#"#><#@ import namespace="System.Linq";#><#@ import namespace=System.Collections.Generic";#><#@参数名称=型号"type=System.Collections.Generic.List"#><?xml version="1.0";编码=utf-8"?><报告 xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";xmlns=http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition"><数据源><数据源名称=数据源1"><连接属性><DataProvider>System.Data.DataSet</DataProvider><ConnectString>/* 本地连接 */</ConnectString></ConnectionProperties><rd:DataSourceID>e9784bb0-a630-49cc-b7f9-8495aca23a6c</rd:DataSourceID></数据源></数据源><数据集><数据集名称=数据集1"><字段><# foreach(模型中的ReportColumn列){#><字段名称=<#=column.Name#>"><DataField><#=column.Name#></DataField><rd:TypeName><#=column.Type.Name#></rd:TypeName></字段><#}#></字段><查询><DataSourceName>DataSource1</DataSourceName><CommandText>/* 本地查询 */</CommandText></查询><rd:DataSetInfo><rd:DataSetName/><rd:TableName/><rd:ObjectDataSourceType/></rd:DataSetInfo></数据集></数据集><身体><报告项目><Tablix 名称=Tablix1"><TablixBody><TablixColumns><# foreach(模型中的ReportColumn列){#><TablixColumn><宽度><#=column.WidthInInch#>in</Width></TablixColumn><#}#></TablixColumns><TablixRows><TablixRow><高度>0.25英寸</高度><TablixCells><# foreach(模型中的ReportColumn列){#><TablixCell><单元格内容><文本框名称=<#=column.Name#>文本框><CanGrow>true</CanGrow><KeepTogether>true</KeepTogether><段落><段落><TextRuns><文本运行><值><#=column.Title#></Value><风格/></TextRun></TextRuns><风格/></段落></段落><rd:DefaultName><#=column.Name#>TextBox</rd:DefaultName><风格><边框><颜色>浅灰色</颜色><样式>纯色</样式></边框><BackgroundColor><#=column.HeaderBackColorInHtml#></BackgroundColor><PaddingLeft>2pt</PaddingLeft><PaddingRight>2pt</PaddingRight><PaddingTop>2pt</PaddingTop><PaddingBottom>2pt</PaddingBottom></风格></文本框></CellContents></TablixCell><#}#></TablixCells></TablixRow><TablixRow><高度>0.25英寸</高度><TablixCells><# foreach(模型中的ReportColumn列){#><TablixCell><单元格内容><文本框名称=<#=column.Name#>><CanGrow>true</CanGrow><KeepTogether>true</KeepTogether><段落><段落><TextRuns><文本运行><值><#=column.Expression#></Value><风格/></TextRun></TextRuns><风格/></段落></段落><rd:DefaultName><#=column.Name#></rd:DefaultName><风格><边框><颜色>浅灰色</颜色><样式>纯色</样式></边框><PaddingLeft>2pt</PaddingLeft><PaddingRight>2pt</PaddingRight><PaddingTop>2pt</PaddingTop><PaddingBottom>2pt</PaddingBottom></风格></文本框></CellContents></TablixCell><#}#></TablixCells></TablixRow></TablixRows></TablixBody><TablixColumnHierarchy><TablixMembers><# foreach(模型中的ReportColumn列){#><TablixMember/><#}#></TablixMembers></TablixColumnHierarchy><TablixRowHierarchy><TablixMembers><TablixMember><KeepWithGroup>之后</KeepWithGroup></TablixMember><TablixMember><组名=详细信息"/></TablixMember></TablixMembers></TablixRowHierarchy><DataSetName>DataSet1</DataSetName><Top>0.15625in</Top><左>0.125英寸</左><高度>0.5英寸</高度><宽度>2in</宽度><风格><边框><样式>无</样式></边框></风格></Tablix></ReportItems><高度>0.82292英寸</高度><风格/></身体><宽度>6.5 英寸</宽度><页面><LeftMargin>1in</LeftMargin><RightMargin>1in</RightMargin><TopMargin>1in</TopMargin><BottomMargin>1in</BottomMargin><风格/></页面><rd:ReportID>60987c40-62b1-463b-b670-f3fa81914e33</rd:ReportID><rd:ReportUnitType>英寸</rd:ReportUnitType></报告>

报告表格

在项目中添加一个Form,并在表单中添加一个ReportViewer控件并将此代码放入类中:

public 部分类 ReportForm : Form{公共报表(){初始化组件();ReportColumns = new List();this.Load+=new EventHandler(ReportForm_Load);}公共列表报表列 { 获取;放;}公共对象报告数据 { 获取;放;}private void ReportForm_Load(对象发送者,EventArgs e){var report = new DynamicReport();report.Session = new Dictionary();report.Session[模型"] = this.ReportColumns;报告.初始化();var rds = new Microsoft.Reporting.WinForms.ReportDataSource(DataSet1", this.ReportData);this.reportViewer1.LocalReport.DataSources.Clear();this.reportViewer1.LocalReport.DataSources.Add(rds);var reportContent = System.Text.Encoding.UTF8.GetBytes(report.TransformText());使用 (var stream = new System.IO.MemoryStream(reportContent)){this.reportViewer1.LocalReport.LoadReportDefinition(stream);}this.reportViewer1.RefreshReport();}}

注意

您可以简单地扩展 ReportColumn 模型以及 DynamicReport.tt.我已经使用现有报告创建了模板,我只是使用了一些 t4 代码标签使其动态化.

示例

您可以克隆或下载一个工作示例:

I have a form AdvancedSearchForm with a DataGridView control dgrData and a button Report in C# Winform. On click of the button Report, I wish that a form with a ReportView control be shown with the same columns as in the DataGridView with the same column Headers.

Form with DataGridView and Button

Output expected on clicking Button "Report":

My DatagridView (dgrData) Control is associated with

  1. SQL

"Select Id, c_Name from Country"

  1. ConnectionString

server=localhost;User Id=root;password=root;Persist Security Info=True;database=country_state

To load data to the grid at runtime, I prepare the following DataAdapter:

DataAdapter dataAdapter = DataAdapter.Current;
// I am passing the SQL statement and the table name to my database which knows the ConnectionString within the LoadData function

DataTable dt0 = dataAdapter.LoadData("select Id, c_Name from `country`", "country");
if (dt0 != null) {
   dgrData.DataSource = dt0;
}

Is it possible to call a child Form containing default reportviewer control, which shows report with a table containing columns corresponding to the datagridview (dgrData) along with data dynamically at runtime?

Output expectation in detail:

  1. On click of button, the reportviewer on the target form should get
    associated with the dataSource from the values in the DataGridView. So, the ReportViewer control does not know anything about the data in the report till user clicks on the Report Button at run-time.
  2. I wish the the solution does not require creation of a separate RDLC file, because It causes external dependency, to stop the current flow and create a report file in a report file designer which can be over-whelming to users.
  3. I know nothing about RDLC designer and associating data source (I am willing to learn (^_^), but I cannot force this learning requirement on my team) and binding the data to the report. I would appreciate working coding examples, if your help contains theory.
  4. I know ReportViewer has been around for quite a long time now. Wish that an example solution for 1-1 data mapping between data-grid and ReportViewer was easier to find for someone in the future on SO.

Note: Please let me know if any additional data is required from my side in the comments. To show the current solution, I had to create and RDLC file where I had to put both the connection string and SQL at design time which I wish to avoid in the solution I am looking for. I wish to find a solution where the RDLC file is generated through some modular code that can be used on other solutions as well, rather than having to design it for each form where I have DataGrids.

解决方案

As an option to create RDLC report dynamically at at run-time, you can use Run-Time Text Templates.

In the below example, I've created a simple grid report that can be used to create report dynamically at run-time. You can dynamically add columns to report and set title, width, header back color for column.

In the example, I've filled the template using a DataGridView. But you can use this technique dependent from any kind of contrlol or even use it in web forms.

Sample Usage - Create and Show Dynamic Report

To create and show dynamic report it's enough to add some columns to the ReportForm and then set data and show the form.

var f = new ReportForm();
f.ReportColumns = this.dataGridView1.Columns.Cast<DataGridViewColumn>()
                      .Select(x => new ReportColumn(x.DataPropertyName)
                      { Title = x.HeaderText, Width = x.Width }).ToList();
f.ReportData = this.dataGridView1.DataSource;
f.ShowDialog();

Path to solution

It's enough to add ReportColumn and DynamicReport.tt and ReportForm to your application or even in a reusable library once and then simply use like above example. Follow below steps to create a dynamic report template.

Report Column Model

Create a report column model that contains properties for title, expression, color and so on. We will use this to add columns to report.

using System;
using System.Drawing;
public class ReportColumn
{
    public ReportColumn(string name)
    {
        Name = name;
        Title = name;
        Type = typeof(System.String);
        Width = GetPixelFromInch(1);
        Expression = string.Format("=Fields!{0}.Value", name);
        HeaderBackColor = Color.LightGray;
    }
    public string Name { get; set; }
    public string Title { get; set; }
    public Type Type { get; set; }
    public int Width { get; set; }
    public float WidthInInch
    {
        get { return GetInchFromPixel(Width); }
    }
    public string Expression { get; set; }
    public Color HeaderBackColor { get; set; }
    public string HeaderBackColorInHtml
    {
        get { return ColorTranslator.ToHtml(HeaderBackColor); }
    }
    private int GetPixelFromInch(float inch)
    {
        using (var g = Graphics.FromHwnd(IntPtr.Zero))
            return (int)(g.DpiY * inch);
    }
    private float GetInchFromPixel(int pixel)
    {
        using (var g = Graphics.FromHwnd(IntPtr.Zero))
            return (float)pixel / g.DpiY;
    }
}

Report Template

Add a Run-time Template (Also known as Preprocessed template) to the project and name it DynamicReport.tt and copy this content to the file:

<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ parameter name="Model" type="System.Collections.Generic.List<ReportColumn>"#>
<?xml version="1.0" encoding="utf-8"?>
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
  <DataSources>
    <DataSource Name="DataSource1">
      <ConnectionProperties>
        <DataProvider>System.Data.DataSet</DataProvider>
        <ConnectString>/* Local Connection */</ConnectString>
      </ConnectionProperties>
      <rd:DataSourceID>e9784bb0-a630-49cc-b7f9-8495aca23a6c</rd:DataSourceID>
    </DataSource>
  </DataSources>
  <DataSets>
    <DataSet Name="DataSet1">
      <Fields>
<#    foreach(ReportColumn column in Model){#>
        <Field Name="<#=column.Name#>">
          <DataField><#=column.Name#></DataField>
          <rd:TypeName><#=column.Type.Name#></rd:TypeName>
        </Field>
<#    }#>
      </Fields>
      <Query>
        <DataSourceName>DataSource1</DataSourceName>
        <CommandText>/* Local Query */</CommandText>
      </Query>
      <rd:DataSetInfo>
        <rd:DataSetName />
        <rd:TableName />
        <rd:ObjectDataSourceType />
      </rd:DataSetInfo>
    </DataSet>
  </DataSets>
  <Body>
    <ReportItems>
      <Tablix Name="Tablix1">
        <TablixBody>
          <TablixColumns>
<#    foreach(ReportColumn column in Model){#>
            <TablixColumn>
              <Width><#=column.WidthInInch#>in</Width>
            </TablixColumn>
<#    }#>
          </TablixColumns>
          <TablixRows>
            <TablixRow>
              <Height>0.25in</Height>
              <TablixCells>
<#    foreach(ReportColumn column in Model){#>
                <TablixCell>
                  <CellContents>
                    <Textbox Name="<#=column.Name#>TextBox">
                      <CanGrow>true</CanGrow>
                      <KeepTogether>true</KeepTogether>
                      <Paragraphs>
                        <Paragraph>
                          <TextRuns>
                            <TextRun>
                              <Value><#=column.Title#></Value>
                              <Style />
                            </TextRun>
                          </TextRuns>
                          <Style />
                        </Paragraph>
                      </Paragraphs>
                      <rd:DefaultName><#=column.Name#>TextBox</rd:DefaultName>
                      <Style>
                        <Border>
                          <Color>LightGrey</Color>
                          <Style>Solid</Style>
                        </Border>
                        <BackgroundColor><#=column.HeaderBackColorInHtml#></BackgroundColor>
                        <PaddingLeft>2pt</PaddingLeft>
                        <PaddingRight>2pt</PaddingRight>
                        <PaddingTop>2pt</PaddingTop>
                        <PaddingBottom>2pt</PaddingBottom>
                      </Style>
                    </Textbox>
                  </CellContents>
                </TablixCell>
<#    }#>
              </TablixCells>
            </TablixRow>
            <TablixRow>
              <Height>0.25in</Height>
              <TablixCells>
<#    foreach(ReportColumn column in Model){#>
                <TablixCell>
                  <CellContents>
                    <Textbox Name="<#=column.Name#>">
                      <CanGrow>true</CanGrow>
                      <KeepTogether>true</KeepTogether>
                      <Paragraphs>
                        <Paragraph>
                          <TextRuns>
                            <TextRun>
                              <Value><#=column.Expression#></Value>
                              <Style />
                            </TextRun>
                          </TextRuns>
                          <Style />
                        </Paragraph>
                      </Paragraphs>
                      <rd:DefaultName><#=column.Name#></rd:DefaultName>
                      <Style>
                        <Border>
                          <Color>LightGrey</Color>
                          <Style>Solid</Style>
                        </Border>
                        <PaddingLeft>2pt</PaddingLeft>
                        <PaddingRight>2pt</PaddingRight>
                        <PaddingTop>2pt</PaddingTop>
                        <PaddingBottom>2pt</PaddingBottom>
                      </Style>
                    </Textbox>
                  </CellContents>
                </TablixCell>
<#    }#>
              </TablixCells>
            </TablixRow>
          </TablixRows>
        </TablixBody>
        <TablixColumnHierarchy>
          <TablixMembers>
<#    foreach(ReportColumn column in Model){#>
            <TablixMember />
<#    }#>
          </TablixMembers>
        </TablixColumnHierarchy>
        <TablixRowHierarchy>
          <TablixMembers>
            <TablixMember>
              <KeepWithGroup>After</KeepWithGroup>
            </TablixMember>
            <TablixMember>
              <Group Name="Details" />
            </TablixMember>
          </TablixMembers>
        </TablixRowHierarchy>
        <DataSetName>DataSet1</DataSetName>
        <Top>0.15625in</Top>
        <Left>0.125in</Left>
        <Height>0.5in</Height>
        <Width>2in</Width>
        <Style>
          <Border>
            <Style>None</Style>
          </Border>
        </Style>
      </Tablix>
    </ReportItems>
    <Height>0.82292in</Height>
    <Style />
  </Body>
  <Width>6.5in</Width>
  <Page>
    <LeftMargin>1in</LeftMargin>
    <RightMargin>1in</RightMargin>
    <TopMargin>1in</TopMargin>
    <BottomMargin>1in</BottomMargin>
    <Style />
  </Page>
  <rd:ReportID>60987c40-62b1-463b-b670-f3fa81914e33</rd:ReportID>
  <rd:ReportUnitType>Inch</rd:ReportUnitType>
</Report>

Report Form

Add a Form to project and add a ReportViewer control to the form and put this code in the class:

public partial class ReportForm : Form
{
    public ReportForm()
    {
        InitializeComponent();
        ReportColumns  = new List<ReportColumn>();
        this.Load+=new EventHandler(ReportForm_Load);
    }

    public List<ReportColumn> ReportColumns { get; set; }
    public Object ReportData { get; set; }

    private void ReportForm_Load(object sender, EventArgs e)
    {
        var report = new DynamicReport();
        report.Session = new Dictionary<string, object>();
        report.Session["Model"] = this.ReportColumns;
        report.Initialize();
        var rds = new Microsoft.Reporting.WinForms.ReportDataSource("DataSet1", this.ReportData);
        this.reportViewer1.LocalReport.DataSources.Clear();
        this.reportViewer1.LocalReport.DataSources.Add(rds);
        var reportContent = System.Text.Encoding.UTF8.GetBytes(report.TransformText());
        using (var stream = new System.IO.MemoryStream(reportContent))
        {
            this.reportViewer1.LocalReport.LoadReportDefinition(stream);
        }
        this.reportViewer1.RefreshReport();
    }
}

Note

You can simply extend the ReportColumn model and also DynamicReport.tt. I've created the template using an exiting report, I just used some t4 code tags to make it dynamic.

Example

You can clone or download a working example:

这篇关于在运行时从 DataGridView 动态创建 RDLC 报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆