从 DataGridView 在 run-time 处动态创建 RDLC 报告
Create RDLC report dynamically at run-time from a DataGridView
我在 C# Winform 中有一个带有 DataGridView 控件 dgrData
和按钮 Report
的表单 AdvancedSearchForm
。在单击按钮 Report
时,我希望带有 ReportView 控件的表单显示为具有与具有相同列 Headers 的 DataGridView 中相同的列。
带有 DataGridView 和 Button 的表单
单击“报告”按钮时的预期输出:
我的DatagridView (dgrData
) 控件关联
- SQL
“Select Id, c_Name from Country”
- 连接字符串
server=localhost;User Id=root;password=root;Persist Security Info=True;database=country_state
为了在运行时将数据加载到网格,我准备了以下 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;
}
是否可以调用包含默认 reportviewer 控件的 child 表单,它显示带有 table 的报告,其中包含对应于 datagridview 的列(dgrData
) 以及运行时动态的数据?
详细输出期望:
- 单击按钮后,目标表单上的报表查看器应获得
与 dataSource 中的值关联
DataGridView。因此,在用户单击报表之前,ReportViewer 控件对报表中的数据一无所知
run-time. 处的按钮
- 我希望解决方案不需要创建单独的 RDLC
文件,因为它导致外部依赖,停止当前流
并在报告文件设计器中创建一个报告文件,它可以是
over-whelming 给用户。
- 我对 RDLC 设计器和关联数据源一无所知(我是
愿意学习(^_^),但是我不能强求这个学习要求
在我的团队中)并将数据绑定到报告。我将不胜感激
工作编码示例,如果您的帮助包含理论。
- 我知道 ReportViewer 已经存在很长时间了。希望
data-grid 和之间的 1-1 数据映射的示例解决方案
以后在 SO 上更容易找到 ReportViewer。
注意:如果需要我这边的任何额外数据,请在评论中告诉我。为了显示当前的解决方案,我必须创建一个 RDLC 文件,我必须在设计时将连接字符串和 SQL 放在其中,我希望在我正在寻找的解决方案中避免这样做。我希望找到一个解决方案,其中 RDLC 文件是通过一些模块化代码生成的,这些代码也可以用于其他解决方案,而不是必须为我有 DataGrids 的每个表单设计它。
作为在 run-time 处动态创建 RDLC
报告的选项,您可以使用 Run-Time Text Templates.
在下面的示例中,我创建了一个简单的网格报表,可用于在 run-time 动态创建报表。您可以动态添加列以报告并设置标题、宽度、header 列的背景颜色。
在示例中,我使用 DataGridView
填充了模板。但是您可以使用这种依赖于任何类型控件的技术,甚至可以在 Web 表单中使用它。
示例用法 - 创建和显示动态报告
要创建和显示动态报告,只需向 ReportForm
添加一些列,然后设置数据并显示表单。
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();
解决之道
只需将 ReportColumn
和 DynamicReport.tt
以及 ReportForm
添加到您的应用程序中,甚至在可重用的库中添加一次,然后像上面的示例一样简单地使用。按照以下步骤创建动态报告模板。
报表列模型
创建一个包含标题、表达式、颜色等属性的报表列模型。我们将使用它来添加要报告的列。
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;
}
}
报告模板
在项目中添加一个Run-time模板(也称为预处理模板)并将其命名为DynamicReport.tt
并将此内容复制到文件中:
<#@ 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>
报告表
在项目中添加一个Form
并在窗体中添加一个ReportViewer
控件并将此代码放在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();
}
}
备注
您可以简单地扩展 ReportColumn
模型以及 DynamicReport.tt
。我使用现有报告创建了模板,我只是使用了一些 t4 代码标签使其动态化。
例子
您可以克隆或下载工作示例:
我在 C# Winform 中有一个带有 DataGridView 控件 dgrData
和按钮 Report
的表单 AdvancedSearchForm
。在单击按钮 Report
时,我希望带有 ReportView 控件的表单显示为具有与具有相同列 Headers 的 DataGridView 中相同的列。
带有 DataGridView 和 Button 的表单
单击“报告”按钮时的预期输出:
我的DatagridView (dgrData
) 控件关联
- SQL
“Select Id, c_Name from Country”
- 连接字符串
server=localhost;User Id=root;password=root;Persist Security Info=True;database=country_state
为了在运行时将数据加载到网格,我准备了以下 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;
}
是否可以调用包含默认 reportviewer 控件的 child 表单,它显示带有 table 的报告,其中包含对应于 datagridview 的列(dgrData
) 以及运行时动态的数据?
详细输出期望:
- 单击按钮后,目标表单上的报表查看器应获得
与 dataSource 中的值关联 DataGridView。因此,在用户单击报表之前,ReportViewer 控件对报表中的数据一无所知 run-time. 处的按钮
- 我希望解决方案不需要创建单独的 RDLC 文件,因为它导致外部依赖,停止当前流 并在报告文件设计器中创建一个报告文件,它可以是 over-whelming 给用户。
- 我对 RDLC 设计器和关联数据源一无所知(我是 愿意学习(^_^),但是我不能强求这个学习要求 在我的团队中)并将数据绑定到报告。我将不胜感激 工作编码示例,如果您的帮助包含理论。
- 我知道 ReportViewer 已经存在很长时间了。希望 data-grid 和之间的 1-1 数据映射的示例解决方案 以后在 SO 上更容易找到 ReportViewer。
注意:如果需要我这边的任何额外数据,请在评论中告诉我。为了显示当前的解决方案,我必须创建一个 RDLC 文件,我必须在设计时将连接字符串和 SQL 放在其中,我希望在我正在寻找的解决方案中避免这样做。我希望找到一个解决方案,其中 RDLC 文件是通过一些模块化代码生成的,这些代码也可以用于其他解决方案,而不是必须为我有 DataGrids 的每个表单设计它。
作为在 run-time 处动态创建 RDLC
报告的选项,您可以使用 Run-Time Text Templates.
在下面的示例中,我创建了一个简单的网格报表,可用于在 run-time 动态创建报表。您可以动态添加列以报告并设置标题、宽度、header 列的背景颜色。
在示例中,我使用 DataGridView
填充了模板。但是您可以使用这种依赖于任何类型控件的技术,甚至可以在 Web 表单中使用它。
示例用法 - 创建和显示动态报告
要创建和显示动态报告,只需向 ReportForm
添加一些列,然后设置数据并显示表单。
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();
解决之道
只需将 ReportColumn
和 DynamicReport.tt
以及 ReportForm
添加到您的应用程序中,甚至在可重用的库中添加一次,然后像上面的示例一样简单地使用。按照以下步骤创建动态报告模板。
报表列模型
创建一个包含标题、表达式、颜色等属性的报表列模型。我们将使用它来添加要报告的列。
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;
}
}
报告模板
在项目中添加一个Run-time模板(也称为预处理模板)并将其命名为DynamicReport.tt
并将此内容复制到文件中:
<#@ 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>
报告表
在项目中添加一个Form
并在窗体中添加一个ReportViewer
控件并将此代码放在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();
}
}
备注
您可以简单地扩展 ReportColumn
模型以及 DynamicReport.tt
。我使用现有报告创建了模板,我只是使用了一些 t4 代码标签使其动态化。
例子
您可以克隆或下载工作示例: