首先封装一个公共类,统一来操作RDLC报表
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Xml; using System.Data; using Microsoft.Reporting.WebForms; using System.Text; using System.Collections; using System.IO; using System.Reflection; using System.Xml.Serialization; namespace WebApplication3 { public class DynamicReport : IDynamicReport { #region 空白文档 /// <summary> /// 空白文档的xml文件 /// </summary> protected string _docTemplate = "<?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=\"DummyDataSource\">" + " <ConnectionProperties>" + " <DataProvider>SQL</DataProvider>" + " <ConnectString />" + " </ConnectionProperties>" + " <rd:DataSourceID>3eecdab9-6b4b-4836-ad62-95e4aee65ea8</rd:DataSourceID>" + " </DataSource>" + "</DataSources>" + "<DataSets>@DataSets</DataSets>" + "<Body>" + "<ReportItems>@Title@Tablix" + "</ReportItems>" + "<Style />" + "<Height>8cm</Height>" + "</Body>" + "<Width>17cm</Width>" + "<Page>" + "<PageHeight>29.7cm</PageHeight>" + "<PageWidth>21cm</PageWidth>" + "<LeftMargin>1.8cm</LeftMargin>" + "<RightMargin>1.8cm</RightMargin>" + "<TopMargin>1.8cm</TopMargin>" + "<BottomMargin>1.8cm</BottomMargin>" + "<ColumnSpacing>0.13cm</ColumnSpacing>" + "<Style />" + "</Page>" + "<rd:ReportID>809f16cf-ea78-4469-bf43-965c4afe69d0</rd:ReportID>" + "<rd:ReportUnitType>Cm</rd:ReportUnitType>" + "</Report>"; protected string TitlePattern = " <Textbox Name=\"Textbo@TextboxName\"> " + @"<CanGrow>true</CanGrow> <KeepTogether>true</KeepTogether> <Paragraphs> <Paragraph> <TextRuns> <TextRun> <Value>@Title</Value> <Style>@FontStyle</Style> </TextRun> </TextRuns> <Style>@Style</Style> </Paragraph> </Paragraphs> <rd:DefaultName>Textbo@TextboxName</rd:DefaultName> <Top>@TopPositioncm</Top> <Left>1cm</Left> <Height>0.83813cm</Height> <Width>14.35207cm</Width> <ZIndex>1</ZIndex> <Style> <Border> <Style>None</Style> </Border> <PaddingLeft>2pt</PaddingLeft> <PaddingRight>2pt</PaddingRight> <PaddingTop>2pt</PaddingTop> <PaddingBottom>2pt</PaddingBottom> </Style> </Textbox>"; #endregion private ReportViewer _report; private List<ReportColoumStyle> _coloumStyle = new List<ReportColoumStyle>(); private List<ReportItemPattern> _reportItemPatterns = new List<ReportItemPattern>(); private List<string> _reportTitlePatterns = new List<string>(); private List<ReportItemPattern> _reportHeadPatterns = new List<ReportItemPattern>(); internal const float ColoumWidth = 1.6F; //行宽 public ReportType ReportType { get; set; } public DynamicReport() { } /// <summary> /// 从现有报表中加载报表并进行修改 /// </summary> /// <param name="url"></param> public void LoadReport(string url) { try { _docTemplate = File.ReadAllText(url); } catch (Exception ex) { } } public void SetReport(ReportViewer reportViewer) { this._report = reportViewer; } public void SetColoumStyle(List<ReportColoumStyle> coloumStyle) { this._coloumStyle = coloumStyle; } public void AddText(string text) { if (!string.IsNullOrEmpty(text)) { var pos = CaculatePlacePostion(); var titlePattern = TitlePattern .Replace("@Title", text) .Replace("@TopPosition", pos.ToString()) .Replace("@TextboxName", _reportTitlePatterns.Count.ToString()) .Replace("@FontStyle", "<FontFamily>微软雅黑</FontFamily><FontSize>12pt</FontSize>") .Replace("@Style", "<TextAlign>Center</TextAlign>"); _reportTitlePatterns.Add(titlePattern); } } public void AddText(string text, int chapterGrade) { if (!string.IsNullOrEmpty(text)) { var pos = CaculatePlacePostion(); var titlePattern = TitlePattern .Replace("@Title", text) .Replace("@TopPosition", pos.ToString()) .Replace("@TextboxName", _reportTitlePatterns.Count.ToString()); switch (chapterGrade) { case 1: titlePattern = titlePattern.Replace("@FontStyle", "<FontFamily>宋体</FontFamily><FontSize>18pt</FontSize><Color>#000000</Color>") .Replace("@Style", "<TextAlign>Center</TextAlign>"); break; case 2: titlePattern = titlePattern.Replace("@FontStyle", "<FontFamily>黑体</FontFamily><FontSize>14pt</FontSize><Color>#000000</Color>") .Replace("@Style", "<TextAlign>Left</TextAlign>"); break; case 3: titlePattern = titlePattern.Replace("@FontStyle", "<FontFamily>宋体</FontFamily><FontSize>12pt</FontSize><FontWeight>Bold</FontWeight>") .Replace("@Style", "<TextAlign>Left</TextAlign>"); break; default: case 10: titlePattern = titlePattern.Replace("@FontStyle", "<FontFamily>宋体</FontFamily><FontSize>12pt</FontSize>") .Replace("@Style", "<LineHeight>22pt</LineHeight>"); break; } _reportTitlePatterns.Add(titlePattern); } } public void AddData<T>(IEnumerable<T> data) { if (data.Count() != 0) { var properites = typeof(T).GetProperties(); //得到实体类属性的集合 AddReportItemPattern(properites.Select(p => p.Name).ToArray(), data); } } public void AddData(DataTable dataTable) { if (dataTable != null) { var coloumNames = new List<string>(); foreach (DataColumn dataColumn in dataTable.Columns) { var protertyName = dataColumn.ColumnName; coloumNames.Add(protertyName); } AddReportItemPattern(coloumNames.ToArray(), dataTable); } } /// <summary> /// 计算开始摆放的位置 /// </summary> /// <returns></returns> protected float CaculatePlacePostion() { //每个标题的高度 float titleCount = _reportTitlePatterns.Count * 1f; //每个数据表的高度 float itemCount = _reportItemPatterns.Count * 2f; // 每个空表头的高度 float emptyItemCount = _reportHeadPatterns.Count * 0.5f; switch (ReportType) { case ReportType.Tables: return titleCount + itemCount + emptyItemCount + 0.5f; case ReportType.Chart: case ReportType.Finally: return titleCount + itemCount + emptyItemCount + 25.7f; } return 0f; } /// <summary> /// 增加一个报表 /// </summary> /// <param name="coloumNames"></param> /// <param name="data"></param> /// <param name="dataType"></param> protected void AddReportItemPattern(string[] coloumNames, dynamic data) { var fields = new StringBuilder(); var coloums = new StringBuilder(); var tablixHearders = new StringBuilder(); var tablixCells = new StringBuilder(); var tablixMembers = new StringBuilder(); var currentNamePrefix = _reportItemPatterns.Count + _reportHeadPatterns.Count + 1; var tableWidth = 0F; var dataRows = GetDataRowsCount(data); //数据行数 foreach (var coloumName in coloumNames) { var coloumWidth = ColoumWidth; var textAlign = TextAlign.Right; var reportColoumStyle = _coloumStyle.FirstOrDefault(r => r.ColoumName == coloumName); if (reportColoumStyle != null) { textAlign = reportColoumStyle.TextAlign; coloumWidth = reportColoumStyle.ColoumWidth; } tableWidth += coloumWidth; var bottomBorder = string.Empty; //每个单元格底部border if (dataRows == 0) { bottomBorder = "<BottomBorder><Style>None</Style></BottomBorder>"; } var coloumValue = coloumName; //例外,如果coloumName包含Coloum之类的字段,则将value设成空 if (coloumName.IndexOf("Column", System.StringComparison.Ordinal) > -1) { coloumValue = " "; } fields.AppendFormat( "<Field Name=\"{0}\"><DataField>{0}</DataField><rd:TypeName>System.String</rd:TypeName></Field>", coloumName); coloums.AppendFormat("<TablixColumn><Width>{0}cm</Width></TablixColumn>", coloumWidth); tablixHearders.AppendFormat("<TablixCell><CellContents>" + "<Textbox Name=\"Textbox{0}{1}\"><CanGrow>true</CanGrow><KeepTogether>true</KeepTogether><Paragraphs><Paragraph>" + "<TextRuns><TextRun><Value>{2}</Value><Style /></TextRun></TextRuns><Style><TextAlign>Center</TextAlign></Style></Paragraph></Paragraphs>" + "<rd:DefaultName>Textbox{0}{1}</rd:DefaultName><Style><Border><Color>LightGrey</Color><Style>Solid</Style></Border>{3}" + "<PaddingLeft>2pt</PaddingLeft><PaddingRight>2pt</PaddingRight><PaddingTop>2pt</PaddingTop><PaddingBottom>2pt</PaddingBottom></Style></Textbox></CellContents></TablixCell>", coloumName, currentNamePrefix, coloumValue, bottomBorder); tablixCells.AppendFormat( "<TablixCell><CellContents><Textbox Name=\"{0}{1}1\"><CanGrow>true</CanGrow><KeepTogether>true</KeepTogether>" + "<Paragraphs><Paragraph><TextRuns><TextRun><Value>=Fields!{0}.Value</Value><Style /></TextRun></TextRuns><Style><TextAlign>{2}</TextAlign></Style></Paragraph></Paragraphs>" + "<rd:DefaultName>{0}{1}1</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>", coloumName, currentNamePrefix, textAlign); tablixMembers.AppendFormat("<TablixMember />"); } //计算表格应该离左边多少距离 var leftPosition = 0F; if (tableWidth < 17) { leftPosition = (17F - tableWidth) / 2; } var dataSetName = string.Format("Data{0}", _reportItemPatterns.Count + _reportHeadPatterns.Count + 1); var reportItemPattern = new ReportItemPattern(); reportItemPattern.Data = DynamicReportExtension.RemoveZeroData(data); reportItemPattern.DataSetName = dataSetName; reportItemPattern.DataSetString = reportItemPattern.DataSetPattern .Replace("@DataSetName", dataSetName) .Replace("@Fields", fields.ToString()); reportItemPattern.TablixString = reportItemPattern.TablixPattern .Replace("@DataSetName", dataSetName) .Replace("@TablixColumns", coloums.ToString()) .Replace("@TablixHeader", tablixHearders.ToString()) .Replace("@TablixCells", tablixCells.ToString()) .Replace("@TablixMember", tablixMembers.ToString()) .Replace("@TopPosition", CaculatePlacePostion().ToString()) .Replace("@LeftPostion", leftPosition.ToString()); //读取行数,如果是空行就加到新的 if (dataRows == 0) { _reportHeadPatterns.Add(reportItemPattern); } else { _reportItemPatterns.Add(reportItemPattern); } } /// <summary> /// 得到某种类型数据的数量 /// </summary> /// <param name="data"></param> /// <returns></returns> private int GetDataRowsCount(dynamic data) { if (data is DataTable) { return ((DataTable)data).Rows.Count; } else if (data is IEnumerable) { return Enumerable.Count(data); } else return 0; } /// <summary> /// 最终显示报表 /// </summary> public void ShowReport() { //将每一个patter转换 if (_reportItemPatterns.Count > 0 || _reportTitlePatterns.Count > 0) { var dataSetsString = new StringBuilder(); var tablixString = new StringBuilder(); foreach (var reportItemPattern in _reportItemPatterns) { dataSetsString.Append(reportItemPattern.DataSetString); tablixString.Append(reportItemPattern.TablixString); } foreach (var reportItemPattern in _reportHeadPatterns) { dataSetsString.Append(reportItemPattern.DataSetString); tablixString.Append(reportItemPattern.TablixString); } var reportTitleString = new StringBuilder(); foreach (var reportTitlePattern in _reportTitlePatterns) { reportTitleString.Append(reportTitlePattern); } //把文档中的文字替换掉 switch (ReportType) { case ReportType.Tables: _docTemplate = _docTemplate.Replace("@DataSets", dataSetsString.ToString()) .Replace("@Tablix", tablixString.ToString()) .Replace("@Title", reportTitleString.ToString()); break; case ReportType.Chart: break; case ReportType.Finally: //替换datasetstring var pos = _docTemplate.IndexOf("<Body>", StringComparison.Ordinal); _docTemplate = _docTemplate.Insert(pos, string.Format( "<DataSources><DataSource Name=\"DummyDataSource\"><ConnectionProperties><DataProvider>SQL</DataProvider><ConnectString /></ConnectionProperties><rd:DataSourceID>3eecdab9-6b4b-4836-ad62-95e4aee65ea8</rd:DataSourceID></DataSource></DataSources><DataSets>{0}</DataSets>", dataSetsString)); //替换Tablix pos = _docTemplate.IndexOf("<ReportItems>", StringComparison.Ordinal); _docTemplate = _docTemplate.Insert(pos + 13, tablixString.ToString()); //替换title _docTemplate = _docTemplate.Insert(pos + 13, reportTitleString.ToString()); break; } var doc = new XmlDocument(); doc.LoadXml(_docTemplate); Stream stream = GetRdlcStream(doc); //加载报表定义 _report.LocalReport.LoadReportDefinition(stream); _report.LocalReport.DataSources.Clear(); foreach (var reportItemPattern in _reportItemPatterns) { _report.LocalReport.DataSources .Add(new ReportDataSource(reportItemPattern.DataSetName + "Data", reportItemPattern.Data)); } foreach (var reportItemPattern in _reportHeadPatterns) { _report.LocalReport.DataSources .Add(new ReportDataSource(reportItemPattern.DataSetName + "Data", reportItemPattern.Data)); } _report.LocalReport.Refresh(); } } /// <summary> /// 序列化到内存流 /// </summary> /// <returns></returns> protected Stream GetRdlcStream(XmlDocument xmlDoc) { Stream ms = new MemoryStream(); XmlSerializer serializer = new XmlSerializer(typeof(XmlDocument)); serializer.Serialize(ms, xmlDoc); ms.Position = 0; return ms; } } public interface IDynamicReport { void SetReport(ReportViewer reportViewer); void AddData<T>(IEnumerable<T> data); void AddData(DataTable dataTable); void ShowReport(); void LoadReport(string reportPath); void SetColoumStyle(List<ReportColoumStyle> coloumStyle); void AddText(string title); } public class ReportColoumStyle { public string ColoumName { get; set; } public float ColoumWidth { get; set; } public TextAlign TextAlign { get; set; } public ReportColoumStyle() { ColoumWidth = DynamicReport.ColoumWidth; } } public enum TextAlign { Left, Center, Right } public enum ReportType { Tables, Chart, Finally } internal enum DataType { DataTable, Enumerable } internal class ReportItemPattern { public string DataSetName { get; set; } public string DataSetString { get; set; } public string TablixString { get; set; } public dynamic Data { get; set; } public string DataSetPattern { get { return " <DataSet Name=\"@DataSetNameData\">" + " <Fields>@Fields</Fields>" + " <Query>" + " <DataSourceName>DummyDataSource</DataSourceName>" + " <CommandText />" + " </Query>" + " </DataSet>"; } } public string TablixPattern { get { return " <Tablix Name=\"Tablix@DataSetName\">" + " <TablixBody>" + " <TablixColumns>@TablixColumns</TablixColumns>" + " <TablixRows>" + " <TablixRow>" + " <Height>0.23622in</Height>" + " <TablixCells>@TablixHeader</TablixCells>" + " </TablixRow>" + " <TablixRow>" + " <Height>0.23622in</Height>" + " <TablixCells>@TablixCells</TablixCells>" + " </TablixRow>" + " </TablixRows>" + " </TablixBody>" + " <TablixColumnHierarchy>" + " <TablixMembers>@TablixMember</TablixMembers>" + " </TablixColumnHierarchy>" + " <TablixRowHierarchy>" + " <TablixMembers>" + " <TablixMember>" + " <KeepWithGroup>After</KeepWithGroup>" + " </TablixMember>" + " <TablixMember>" + " <Group Name=\"详细信息@DataSetName\" />" + " </TablixMember>" + " </TablixMembers>" + " </TablixRowHierarchy>" + " <DataSetName>@DataSetNameData</DataSetName>" + " <Top>@TopPositioncm</Top>" + " <Left>@LeftPostioncm</Left>" + " <Height>1.2cm</Height>" + " <Width>14.35207cm</Width>" + " <Style>" + " <Border>" + " <Style>None</Style>" + " </Border>" + " </Style>" + "</Tablix>"; } } } internal static class DynamicReportExtension { public static dynamic RemoveZeroData(this object data) { if (data is DataTable) { return ((DataTable)data).ChangeEachColumnTypeToString(); } else if (data is IEnumerable) { var _data = ((IEnumerable)data).Cast<object>(); return _data.CopyToDataTable().RemoveZeroData(); } return data; } public static DataTable ChangeEachColumnTypeToString(this DataTable dt) { DataTable tempdt = new DataTable(); foreach (DataColumn dc in dt.Columns) { DataColumn tempdc = new DataColumn(); tempdc.ColumnName = dc.ColumnName; tempdc.DataType = typeof(String); tempdt.Columns.Add(tempdc); } int coloumCount = dt.Columns.Count; foreach (DataRow dr in dt.Rows) { var newrow = tempdt.NewRow(); for (int i = 0; i < coloumCount; i++) { var value = dr[i].ToString(); switch (value) { case "0": case "0.00%": newrow[i] = "-"; break; default: newrow[i] = value; break; } } tempdt.Rows.Add(newrow); } return tempdt; } } internal static class DataSetLinqOperators { public static DataTable CopyToDataTable<T>(this IEnumerable<T> source) { return new ObjectShredder<T>().Shred(source, null, null); } public static DataTable CopyToDataTable<T>(this IEnumerable<T> source, DataTable table, LoadOption? options) { return new ObjectShredder<T>().Shred(source, table, options); } } internal class ObjectShredder<T> { private FieldInfo[] _fi; private PropertyInfo[] _pi; private Dictionary<string, int> _ordinalMap; private Type _type; public ObjectShredder() { _type = typeof(T); _fi = _type.GetFields(); _pi = _type.GetProperties(); _ordinalMap = new Dictionary<string, int>(); } public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options) { if (typeof(T).IsPrimitive) { return ShredPrimitive(source, table, options); } if (table == null) { table = new DataTable(typeof(T).Name); } // now see if need to extend datatable base on the type T + build ordinal map table = ExtendTable(table, typeof(T)); table.BeginLoadData(); using (IEnumerator<T> e = source.GetEnumerator()) { while (e.MoveNext()) { if (options != null) { table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options); } else { table.LoadDataRow(ShredObject(table, e.Current), true); } } } table.EndLoadData(); return table; } public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options) { if (table == null) { table = new DataTable(typeof(T).Name); } if (!table.Columns.Contains("Value")) { table.Columns.Add("Value", typeof(T)); } table.BeginLoadData(); using (IEnumerator<T> e = source.GetEnumerator()) { Object[] values = new object[table.Columns.Count]; while (e.MoveNext()) { values[table.Columns["Value"].Ordinal] = e.Current; if (options != null) { table.LoadDataRow(values, (LoadOption)options); } else { table.LoadDataRow(values, true); } } } table.EndLoadData(); return table; } public DataTable ExtendTable(DataTable table, Type type) { // value is type derived T, may need to extend table. foreach (FieldInfo f in type.GetFields()) { if (!_ordinalMap.ContainsKey(f.Name)) { DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name] : table.Columns.Add(f.Name, f.FieldType); _ordinalMap.Add(f.Name, dc.Ordinal); } } foreach (PropertyInfo p in type.GetProperties()) { if (!_ordinalMap.ContainsKey(p.Name)) { DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name] : table.Columns.Add(p.Name, p.PropertyType); _ordinalMap.Add(p.Name, dc.Ordinal); } } return table; } public object[] ShredObject(DataTable table, T instance) { FieldInfo[] fi = _fi; PropertyInfo[] pi = _pi; if (instance.GetType() != typeof(T)) { ExtendTable(table, instance.GetType()); fi = instance.GetType().GetFields(); pi = instance.GetType().GetProperties(); } Object[] values = new object[table.Columns.Count]; foreach (FieldInfo f in fi) { values[_ordinalMap[f.Name]] = f.GetValue(instance); } foreach (PropertyInfo p in pi) { values[_ordinalMap[p.Name]] = p.GetValue(instance, null); } return values; } } }下面的情况在前端绑定就可以
private DataTable CreateData() { DataTable dt = new DataTable(); dt.Columns.Add("专业名称"); dt.Columns.Add("学院"); dt.Columns.Add("就业去向"); for (int i = 0; i < 100; i++) { DataRow dr = dt.NewRow(); dr[0] = "我是"+i; dr[1] = "三年级"; dr[2] = "二班"; dt.Rows.Add(dr); } return dt; } private void DynamicBindRV() { //new一个报表类对象 var dynamicReport = new DynamicReport { ReportType = ReportType.Tables }; //设置报表为本地报表 dynamicReport.SetReport(this.ReportViewer1); //设置列宽度和对齐方式(可选) dynamicReport.SetColoumStyle(new List<ReportColoumStyle>() { new ReportColoumStyle(){ColoumName = "专业名称", ColoumWidth = 4F}, new ReportColoumStyle() {ColoumName = "学院", ColoumWidth = 3.5F}, new ReportColoumStyle(){ColoumName = "就业去向", ColoumWidth = 10F}, }); //加入标题 dynamicReport.AddText("测试"); //加入数据 dynamicReport.AddData(CreateData()); //设置导出报表的名称 ReportViewer1.LocalReport.DisplayName = "测试"; //处理报表数据并显示 dynamicReport.ShowReport(); }
原文地址:http://blog.csdn.net/fwj380891124/article/details/44309241