Create RDLC report dynamically at run-time from a DataGridView

前端 未结 1 1230
说谎
说谎 2020-11-30 13:12

I have a form AdvancedSearchForm with a DataGridView control dgrData and a button Report in C# Winform. On click of t

相关标签:
1条回答
  • 2020-11-30 13:39

    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:

    • r-aghaei/DynamicRdlcReport
    • Download Zip
    0 讨论(0)
提交回复
热议问题