动态生成RDLC报表

时间:2023-01-11 09:12:05

动态生成RDLC报表

前段时间,做了RDLC报表,主要是三块功能:

1、从DataGrid提取(包括最新的增删改)数据,自动生成对应的RDLC报表文件(以流的形式驻存在内存中),用ReportViewer类来展示、打印、排版、预览、分页

   提供一个提取任意控件数据的通用接口,然后拼接成DataTable这种网状的格子。DataGrid里修改、增加、删除等数据变动,立即同步更新到报表

2、给一个简单的RDLC模板,提供表头的字体格式和表内部数据等样式相关的信息,然后再用DataGrid里提取的数据,生成DataTable和其它必需信息,填充到报表里,

自动调整报表格式

3、做了一个TreeView,很简单;根据报表文件名称,切换左侧TreeView的Item,就加载不同的报表,显示数据。用了一点反射的知识

转载请注明出处: https://www.cnblogs.com/NaughtyCat/p/auto-generate-report.html

第一步:根据 Report Definition Language (RDL) 生成对应的类和命名空间。

1、去 http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition/下载ReportDefinition2010.xsd。

注意:ReportDefinition和Visual Studio发布的有个时间差,官网上有ReportDefinition2005版和ReportDefinition2008版。ReportDefinition2005版,VS2008及以后才支持;

ReportDefinition2008版,VS2010及以后支持。2010版,要VS2012以后才支持。我的是VS2010,用ReportDefinition2008版就好。

2、找XML Schema Definition Tool (Xsd.exe),Windows操作系统会自带(微软会自带很多功能强大的exe,要是开源就好了)。For more detail,please refer to:

官网有详细的命令使用说明 https://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx

Below is my CMD in administator mode:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64>xsd

/c /n:RDLC

/out:C:\Users\admin\Desktop\RDLCReportResearch

C:\Users\admin\Desktop\RDLCReportResearch\ReportDefinition.xsd

完了,生成的是这么个样子(ReportDefinition2005的生成出来有8000行左右,ReportDefinition2008的及以后有10000多行,贴一部分,样子参照下面代码)

using System.Xml.Serialization;

    /// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition", IsNullable=false)]
public partial class Report { private object[] itemsField; private ItemsChoiceType80[] itemsElementNameField; private System.Xml.XmlAttribute[] anyAttrField; /// <remarks/>
[System.Xml.Serialization.XmlAnyElementAttribute()]
[System.Xml.Serialization.XmlElementAttribute("Author", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("AutoRefresh", typeof(uint))]
[System.Xml.Serialization.XmlElementAttribute("Body", typeof(BodyType))]
[System.Xml.Serialization.XmlElementAttribute("Classes", typeof(ClassesType))]
[System.Xml.Serialization.XmlElementAttribute("Code", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("CodeModules", typeof(CodeModulesType))]
[System.Xml.Serialization.XmlElementAttribute("ConsumeContainerWhitespace", typeof(bool))]

ReportDefinition.cs

第二步:创建RDLCGenerator类和TablixRDLCGenerator类

1、根据下载的Report Definition Language(RDL)和一个创建的简单的RDLC文件,知道RDLC文件基本要有哪几部分组成;然后层层嵌套创建就出来了,很简单。

2-1、Tablix是关键数据区,GotReportViewer上面的例子,DynamicMatrix和DynamicTable是根据RDL2005来做的,RDL2008以后,就是一个Tablix:

2-2、Tablix的主要数据区域: TablixHierarchyType CreateTablixColumnHierarchy()和TablixHierarchyType CreateTablixRowHierarchy()

2-3、对于HeaderRow和DataRow关键就在下面的不同。

         private LocIDStringWithDataTypeAttribute CreateTablixTextRunValue(bool isHeaderCell, string name)
{
LocIDStringWithDataTypeAttribute v = new LocIDStringWithDataTypeAttribute();
v.Value = isHeaderCell ? name : "=Fields!" + name + ".Value";
v.DataType = StringWithDataTypeAttributeDataType.String;
return v;
}

CreateTablixTextRunValue

2-4、DataSet的名字一定要和ReportDataSource里的名字完全匹配

RdlcGenerator的Read和Write方法比较重要。

    /// table + matrix = tablix
/// Microsoft 用一个tablix来支持Table(表), Matrix(矩阵) and List(列表)这三种报表项
/// 整合了table和matrix的功能
       #region Properties

        // DataGrid 的DataGridColumn的Header
private List<string> headerNames = new List<string>();
public List<string> HeaderNames
{
get { return headerNames; }
} // 对应DataGrid Binding的Path
private List<string> fieldNames = new List<string>();
public List<string> FieldNames
{
get { return fieldNames; }
} // 对应DataGrid Column的ActualWdith(因为实际的窗口宽度会重新计算)
private List<double> widths = new List<double>();
public List<double> Widths
{
get { return widths; }
} // 如果没有更新过页面设置,用ReportViewer的默认页面设置;否则用最新的页面设置
public PageSettings PageSettings { get; set; } public string Headline { get; set; } public string DataSourceName { get; set; } public string DataSetName { get; set; } #endregion #region Methods // 一层套一层,把xml构造出来
private Report CreateReport()
{
Report report = new Report(); report.Items = new object[]
{
CreateDataSources(),
CreateDataSets(),
CreateBody(),
CalcReportWidth(),
CreatePage(),
};
report.ItemsElementName = new ItemsChoiceType80[]
{
ItemsChoiceType80.DataSources,
ItemsChoiceType80.DataSets,
ItemsChoiceType80.Body,
ItemsChoiceType80.Width,
ItemsChoiceType80.Page,
}; return report;
} private DataSourcesType CreateDataSources()
{
DataSourcesType dataSources = new DataSourcesType();
dataSources.DataSource = new DataSourceType[] { CreateDataSource() };
return dataSources;
} private DataSourceType CreateDataSource()
{
DataSourceType dataSource = new DataSourceType();
dataSource.Name = String.IsNullOrEmpty(DataSetName) ? "TBReport" : DataSetName;
dataSource.Items = new object[] { CreateDataSourceConnectionProperties() };
return dataSource;
} private ConnectionPropertiesType CreateDataSourceConnectionProperties()
{
ConnectionPropertiesType connectionProperties = new ConnectionPropertiesType(); connectionProperties.Items = new object[]
{
"System.Data.DataSet",
"/* Local Connection */",
};
connectionProperties.ItemsElementName = new ItemsChoiceType[]
{
ItemsChoiceType.DataProvider,
ItemsChoiceType.ConnectString,
}; return connectionProperties;
} private DataSetsType CreateDataSets()
{
DataSetsType dataSets = new DataSetsType();
dataSets.DataSet = new DataSetType[] { CreateDataSet() };
return dataSets;
} // Query暂时就不要了
private DataSetType CreateDataSet()
{
DataSetType dataSet = new DataSetType();
// DataSetName写死就好
dataSet.Name = "CustomerDataSet";
dataSet.Items = new object[]
{
CreateDataSetFields(),
CreateDataSetQuery(),
}; return dataSet;
} private FieldsType CreateDataSetFields()
{
FieldsType fields = new FieldsType(); // DataSet的具体field由DataGrid的Bingding的Path值决定
if ((fieldNames != null) && (fieldNames.Count > ))
{
fields.Field = new FieldType[fieldNames.Count];
for (int index = ; index < fieldNames.Count; index++)
fields.Field[index] = CreateDataSetField(fieldNames[index]);
} return fields;
} private FieldType CreateDataSetField(string fieldName)
{
FieldType field = new FieldType();
field.Name = fieldName;
field.Items = new object[]
{
fieldName,
// CreateDataSetFieldValue(),
};
return field;
} // 暂时DataType全部用String
private StringWithDataTypeAttribute CreateDataSetFieldValue()
{
StringWithDataTypeAttribute value = new StringWithDataTypeAttribute();
value.DataType = StringWithDataTypeAttributeDataType.String;
return value;
} private QueryType CreateDataSetQuery()
{
QueryType query = new QueryType(); query.Items = new object[]
{
"TBReport",
"/* Local Query */",
};
query.ItemsElementName = new ItemsChoiceType1[]
{
ItemsChoiceType1.DataSourceName,
ItemsChoiceType1.CommandText,
}; return query;
} private BodyType CreateBody()
{
BodyType body = new BodyType(); body.Items = new object[]
{
"4.8in", // Height
CreateReportItems(), // ReportItems
CreateBodyStyle(),
};
return body;
} private ReportItemsType CreateReportItems()
{
ReportItemsType reportItems = new ReportItemsType(); // 这是关键数据区域
TablixRdlcGenerator tablixGen = new TablixRdlcGenerator();
tablixGen.ResetHeaderNames(HeaderNames);
tablixGen.ResetFieldNames(FieldNames); List<string> tablixColumnWidths;
DataGridHelper.CalcTablixColumnWidth(CalcReportWidth(), Widths, out tablixColumnWidths);
tablixGen.ResetWidths(tablixColumnWidths); reportItems.Items = new object[]
{
CreateReportHeadlineTextbox(),
tablixGen.CreateTablix()
}; return reportItems;
} // 创建标题
private TextboxType CreateReportHeadlineTextbox()
{
TextboxType headlineTextbox = new TextboxType();
headlineTextbox.Name = "headlineTextbox"; string left = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Left / 100.0).ToString() + "in";
string width = (PageSettings == null) ? "17cm" :
((double)(PageSettings.PaperSize.Width - PageSettings.Margins.Left - PageSettings.Margins.Right) / 100.0).ToString() + "in"; headlineTextbox.Items = new object[]
{
true,
true,
CreateHeadlineTextboxParagraphs(),
left,
"0.5cm",
"1.0cm",
width,
CreateHeadlineTextboxStyle() };
headlineTextbox.ItemsElementName = new ItemsChoiceType14[]
{
ItemsChoiceType14.CanGrow,
ItemsChoiceType14.KeepTogether,
ItemsChoiceType14.Paragraphs,
ItemsChoiceType14.Left,
ItemsChoiceType14.Top,
ItemsChoiceType14.Height,
ItemsChoiceType14.Width,
ItemsChoiceType14.Style
}; return headlineTextbox;
} private ParagraphsType CreateHeadlineTextboxParagraphs()
{
ParagraphsType headlineParagraphs = new ParagraphsType();
headlineParagraphs.Paragraph = new ParagraphType[] {CreateHeadlineTextboxParagraph()};
return headlineParagraphs;
} private ParagraphType CreateHeadlineTextboxParagraph()
{
ParagraphType pt = new ParagraphType();
pt.Items = new object[]
{
CreateHeadlineTextRuns(),
CreateHeadlineParagraphStyle()
};
pt.ItemsElementName = new ItemsChoiceType12[]
{
ItemsChoiceType12.TextRuns,
ItemsChoiceType12.Style,
};
return pt;
} private TextRunsType CreateHeadlineTextRuns()
{
TextRunsType trt = new TextRunsType();
trt.TextRun = new TextRunType[] { CreateHeadlineTextRun() };
return trt;
} private TextRunType CreateHeadlineTextRun()
{
TextRunType trt = new TextRunType(); trt.Items = new object[]
{
CreateHeadLineTextRunValue(),
CreateHeadlineTextRunStyle()
};
trt.ItemsElementName = new ItemsChoiceType11[]
{
ItemsChoiceType11.Value,
ItemsChoiceType11.Style
}; return trt;
} private LocIDStringWithDataTypeAttribute CreateHeadLineTextRunValue()
{
LocIDStringWithDataTypeAttribute value = new LocIDStringWithDataTypeAttribute();
value.Value = (Headline == null) ? "标题" : Headline;
value.DataType = StringWithDataTypeAttributeDataType.String;
return value;
} private StyleType CreateHeadlineTextRunStyle()
{
StyleType st = new StyleType(); st.Items = new object[]
{
"宋体",
"14pt",
"Bold",
};
st.ItemsElementName = new ItemsChoiceType4[]
{
ItemsChoiceType4.FontFamily,
ItemsChoiceType4.FontSize,
ItemsChoiceType4.FontWeight
}; return st;
} private StyleType CreateHeadlineParagraphStyle()
{
StyleType st = new StyleType();
st.Items = new object[] { "Center" };
st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.TextAlign };
return st;
} private StyleType CreateHeadlineTextboxStyle()
{
StyleType headlineStyle = new StyleType(); headlineStyle.Items = new object[]
{
CreateHeadlineTextboxBorder(),
"2pt",
"2pt",
"2pt",
"2pt"
};
headlineStyle.ItemsElementName = new ItemsChoiceType4[]
{
ItemsChoiceType4.Border,
ItemsChoiceType4.PaddingLeft,
ItemsChoiceType4.PaddingRight,
ItemsChoiceType4.PaddingTop,
ItemsChoiceType4.PaddingBottom
}; return headlineStyle;
} private BorderType CreateHeadlineTextboxBorder()
{
BorderType headlineTextboxBorder = new BorderType();
headlineTextboxBorder.Items = new object[] { "None" };
headlineTextboxBorder.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.Style };
return headlineTextboxBorder;
} private StyleType CreateBodyStyle()
{
return new StyleType();
} /// <summary>
/// 设置页面基本属性—页眉、页脚、页宽、页高、左边距、右边距等
/// </summary>
private PageType CreatePage()
{
PageType page = new PageType(); // 根据微软官方文档,PaperSize.Height, PaperSize.Width and Margins的Left, Right, Top, Bottom are in hundredths of an inch.
string pageHeight = (PageSettings == null) ? "29.7cm" : ((double)PageSettings.PaperSize.Height / 100.0).ToString() + "in";
string pageWidth = (PageSettings == null) ? "21cm" : ((double)PageSettings.PaperSize.Width / 100.0).ToString() + "in";
string leftMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Left / 100.0).ToString() + "in";
string rightMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Right / 100.0).ToString() + "in";
string topMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Top / 100.0).ToString() + "in";
string bottomMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Bottom / 100.0).ToString() + "in"; // TODO:
// 页眉、页脚(后面再做)
page.Items = new object[]
{
//创建Header不能为空
// CreatePageHeader(),
pageHeight,
pageWidth,
leftMargin,
rightMargin,
topMargin,
bottomMargin,
"0.13cm",
};
page.ItemsElementName = new ItemsChoiceType77[]
{
// ItemsChoiceType77.PageHeader,
ItemsChoiceType77.PageHeight,
ItemsChoiceType77.PageWidth,
ItemsChoiceType77.LeftMargin,
ItemsChoiceType77.RightMargin,
ItemsChoiceType77.TopMargin,
ItemsChoiceType77.BottomMargin,
ItemsChoiceType77.ColumnSpacing
}; return page;
} /// <summary>
/// PageHeader和PageFooter也只是TextRun里Value的数据不一样
/// </summary>
/// <returns></returns>
private PageSectionType CreatePageHeader()
{
return new PageSectionType();
} private PageSectionType CreatePageFooter()
{
return new PageSectionType();
} /// <summary>
/// 把Report序列化为流
/// </summary>
/// <param name="stream">根据Report序列化好的流</param>
public void Write(Stream stream)
{
Write(stream, CreateReport());
} public void Write(Stream stream, Report report)
{
new XmlSerializer(typeof(Report)).Serialize(stream, report);
} public Report Read(Stream stream)
{
return (Report)new XmlSerializer(typeof(Report)).Deserialize(stream);
} /// <summary>
/// 把和DataGrid对应的rdlc模板文件反序列化为Report
/// </summary>
/// <param name="rdlcModelFilePath">和DataGrid对应的rdlc模板文件</param>
/// <returns>反序列化之后的Report</returns>
public Report Read(string rdlcModelFilePath)
{
using (var stream = new FileStream(rdlcModelFilePath, FileMode.Open))
{
return Read(stream);
}
} public void Write(string rdlcModelFilePath)
{
using (var stream = new FileStream(rdlcModelFilePath, FileMode.OpenOrCreate))
{
stream.SetLength();
Write(stream);
}
} /// <summary>
/// 计算Report的宽度,页宽 - 左边距 - 右边距
/// </summary>
/// <returns></returns>
public string CalcReportWidth()
{
string reportWidth = String.Empty;
const double size = 100.0;
reportWidth = (PageSettings == null) ? "6.5in" :
((double)(PageSettings.PaperSize.Width - PageSettings.Margins.Left - PageSettings.Margins.Right) / size).ToString() + "in";
return reportWidth;
}

RdlcGenerator.cs

    public class TablixRdlcGenerator
{
#region Properties // DataGrid 的DataGridColumn的Header
private List<string> headerNames = new List<string>();
public List<string> HeaderNames { get { return headerNames; } } // 对应DataGrid Binding的Path
private List<string> fieldNames = new List<string>();
public List<string> FieldNames { get { return fieldNames; } }
public string DataSetName { get; set; } // 对应DataGrid Column的ActualWidth
private List<string> widths = new List<string>();
public List<string> Widths
{
get { return widths; }
} #endregion #region Methods private void ResetValues(List<string> p, List<string> v)
{
p.Clear();
if (v != null)
{
p.AddRange(v);
}
} public void ResetHeaderNames(List<string> hns)
{
ResetValues(HeaderNames, hns);
} public void ResetFieldNames(List<string> fns)
{
ResetValues(FieldNames, fns);
} public void ResetWidths(List<string> widths)
{
ResetValues(Widths, widths);
} /// <summary>
/// 矩阵和Table对应的Tablix稍微有些不一样,如对于矩阵,TablixBody里的表头和数据项
/// 一些值会拆分到TablixColumnHierarchy和TablixRowHierarchy里TablixMember--TablixHeader--CellContents--Textbox
/// 对于DataGrid我们用最简单的Table就好
/// </summary>
/// <returns></returns>
public TablixType CreateTablix()
{
TablixType tablix = new TablixType();
tablix.Name = "dataGridTablix0";
tablix.Items = new object[]
{
// 创建TablixCorner不能创建个空的
// CreateTablixCorner(),
CreateTablixBody(),
CreateTablixColumnHierarchy(),
CreateTablixRowHierarchy(),
true,
true,
CreateDataSetName(),
// Top, Left, Height, Width可具体调整
// Top, Left ---> Location(距离左上角);Height, Width ---> Size
// (Tablix的大小,这个Width不管用,具体是由各个TablixColumn的Width之和决定)
"1.8cm",
"2cm",
"2cm",
"17cm",
CreateTablixStyle(),
};
tablix.ItemsElementName = new ItemsChoiceType73[]
{
// ItemsChoiceType73.TablixCorner,
ItemsChoiceType73.TablixBody,
ItemsChoiceType73.TablixColumnHierarchy,
ItemsChoiceType73.TablixRowHierarchy,
ItemsChoiceType73.RepeatColumnHeaders,
ItemsChoiceType73.RepeatRowHeaders,
ItemsChoiceType73.DataSetName,
ItemsChoiceType73.Top,
ItemsChoiceType73.Left,
ItemsChoiceType73.Height,
ItemsChoiceType73.Width,
ItemsChoiceType73.Style
}; return tablix;
} /// <summary>
/// non-essential element, so make it emtpy temprorily
/// 看样子是表头行,纵向合并的单元格(如纵向两行合并为一行)等相关的
/// </summary>
/// <returns></returns>
private TablixCornerType CreateTablixCorner()
{
return new TablixCornerType();
} private TablixBodyType CreateTablixBody()
{
TablixBodyType tablixBody = new TablixBodyType();
tablixBody.Items = new object[]
{
CreateTablixColumns(),
CreateTablixRows(),
};
return tablixBody;
} private void EnumHeaderNames(Action<int> act)
{
for (int i = ; i < HeaderNames.Count; i++)
{
act(i);
}
} private TablixColumnsType CreateTablixColumns()
{
TablixColumnsType tablixColumns = new TablixColumnsType(); // 根据DataGridColumns的数量来决定创建几列,并且每列要把具体的宽度传进去
tablixColumns.Items = new object[headerNames.Count];
EnumHeaderNames(p =>
{
tablixColumns.Items[p] = CreateTablixColumn(p);
});
return tablixColumns;
} private TablixColumnType CreateTablixColumn(int index)
{
// Width of column,应该根据DataGridColumn.Width来具体设定,暂时给个固定值
return new TablixColumnType() { Items = new object[] { Widths[index] } };
} /// <summary>
/// 对于DataGrid只应有两行,一行是Header,一行是数据
/// 如果有求
/// </summary>
/// <returns>TablixRowsType</returns>
private TablixRowsType CreateTablixRows()
{
TablixRowsType tablixRows = new TablixRowsType();
tablixRows.Items = new object[]
{
CreateTablixRowHeader(),
CreateTablixRowData(),
};
return tablixRows;
} private TablixRowType CreateTablixRowType(bool isHeader)
{
TablixRowType trt = new TablixRowType();
trt.Items = new object[]
{
"0.23622in", // Default height
CreateTablixCells(isHeader), // Header的Cells的内容和Data的Cells的内容应该不同
};
return trt;
} /// <summary>
/// Tablix Header
/// </summary>
/// <returns></returns>
private TablixRowType CreateTablixRowHeader()
{
return CreateTablixRowType(true);
} private TablixRowType CreateTablixRowData()
{
return CreateTablixRowType(false);
} private TablixCellsType CreateTablixCells(bool isHeaerCell)
{
TablixCellsType tablixCells = new TablixCellsType();
// 根据DataGridColumns的数量来决定创建几个Cell, Header应传DataGridColumn.Header数据
tablixCells.Items = new object[HeaderNames.Count];
EnumHeaderNames(p =>
{
tablixCells.Items[p] = CreateTablixCell(isHeaerCell, p);
});
return tablixCells;
} private TablixCellType CreateTablixCell(bool isHeaderCell, int index)
{
TablixCellType tablixCell = new TablixCellType();
// 基本的只要"CellContents"就够了
tablixCell.Items = new object[] { CreateCellContentes(isHeaderCell, index) };
return tablixCell;
} private CellContentsType CreateCellContentes(bool isheaderCell, int index)
{
CellContentsType cellContents = new CellContentsType(); // 对于DataGrid转换的rdlc,通常是一个Textbox。具体可以是Chart、Image、Line、Rectangle、Subreport等等
cellContents.Items = new object[] { CreateTablixCellTextbox(isheaderCell, index) };
cellContents.ItemsElementName = new ItemsChoiceType71[] { ItemsChoiceType71.Textbox }; return cellContents;
} private TextboxType CreateTablixCellTextbox(bool isHeaderCell, int index)
{
TextboxType tablixCellTextbox = new TextboxType();
// 对于Header的Textbox可以复杂一点,多些字体、背景颜色等字段的定义
// Data的简单点//isHeaderCell ? headerNames[index] :
tablixCellTextbox.Name = isHeaderCell ? "TB" + fieldNames[index] : fieldNames[index];
tablixCellTextbox.Items = new object[]
{
true,
true,
CreateTablixCellTextboxParagraphs(isHeaderCell, isHeaderCell ? headerNames[index] : fieldNames[index]),
CreateTablixCellTextboxStyle(),
};
tablixCellTextbox.ItemsElementName = new ItemsChoiceType14[]
{
ItemsChoiceType14.CanGrow,
ItemsChoiceType14.KeepTogether,
ItemsChoiceType14.Paragraphs,
ItemsChoiceType14.Style,
};
return tablixCellTextbox;
} private ParagraphsType CreateTablixCellTextboxParagraphs(bool isHeaderCell, string name)
{
ParagraphsType pt = new ParagraphsType();
pt.Paragraph = new ParagraphType[] { CreateTablixCellTextboxParagraph(isHeaderCell, name) };
return pt;
} private ParagraphType CreateTablixCellTextboxParagraph(bool isHeaderCell, string name)
{
ParagraphType pt = new ParagraphType();
pt.Items = new object[]
{
CreateTablixCellTextboxParagraphTextRuns(isHeaderCell, name),
CreateTablixCellTextboxParagraphStyle(isHeaderCell),
};
pt.ItemsElementName = new ItemsChoiceType12[]
{
ItemsChoiceType12.TextRuns,
ItemsChoiceType12.Style,
};
return pt;
} private TextRunsType CreateTablixCellTextboxParagraphTextRuns(bool isHeaderCell, string name)
{
TextRunsType trt = new TextRunsType();
trt.TextRun = new TextRunType[] { CreateTablixCellTextboxParagraphTextRun(isHeaderCell, name) };
return trt;
} private TextRunType CreateTablixCellTextboxParagraphTextRun(bool isHeaderCell, string name)
{
TextRunType trt = new TextRunType();
trt.Items = new object[]
{
CreateTablixTextRunValue(isHeaderCell, name),
CreateTablixTextRunStyle(isHeaderCell),
};
trt.ItemsElementName = new ItemsChoiceType11[]
{
ItemsChoiceType11.Value,
ItemsChoiceType11.Style,
};
return trt;
} // 数据项和Header的关键不一样就在这个了
private LocIDStringWithDataTypeAttribute CreateTablixTextRunValue(bool isHeaderCell, string name)
{
LocIDStringWithDataTypeAttribute v = new LocIDStringWithDataTypeAttribute();
v.Value = isHeaderCell ? name : "=Fields!" + name + ".Value";
v.DataType = StringWithDataTypeAttributeDataType.String;
return v;
} private StyleType CreateTablixTextRunStyle(bool isHeaderCell)
{
StyleType st = new StyleType();
string fontSize = isHeaderCell ? "11pt" : "10pt";
string FontWeight = isHeaderCell ? "Bold" : "Default";
st.Items = new object[]
{
"宋体",
fontSize,
FontWeight,
};
st.ItemsElementName = new ItemsChoiceType4[]
{
ItemsChoiceType4.FontFamily,
ItemsChoiceType4.FontSize,
ItemsChoiceType4.FontWeight,
};
return st;
} // 暂时设为表头行“居中对齐”,数据行“靠左对齐”;后面可具体定制表头行和数据行的对齐方式
private StyleType CreateTablixCellTextboxParagraphStyle(bool isHeaderCell)
{
StyleType st = new StyleType();
st.Items = new object[] { isHeaderCell ? "Center" : "Left" };
st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.TextAlign };
return st;
} // *****************************
// Header的Color和Style可以和数据不同,下面是默认的Sytle,可自定义
//******************************
private StyleType CreateTablixCellTextboxStyle()
{
StyleType st = new StyleType();
st.Items = new object[]
{
CreateTablixCellTextboxBorder(),
"2pt",
"2pt",
"2pt",
"2pt",
};
st.ItemsElementName = new ItemsChoiceType4[]
{
ItemsChoiceType4.Border,
// ItemsChoiceType4.BackgroundColor, 默认数据没有BackgroundColor
ItemsChoiceType4.PaddingLeft,
ItemsChoiceType4.PaddingRight,
ItemsChoiceType4.PaddingTop,
ItemsChoiceType4.PaddingBottom,
};
return st;
} private BorderType CreateTablixCellTextboxBorder()
{
BorderType bt = new BorderType();
bt.Items = new object[]
{
"Black",
"Solid",
"1pt"
};
bt.ItemsElementName = new ItemsChoiceType2[]
{
ItemsChoiceType2.Color,
ItemsChoiceType2.Style,
ItemsChoiceType2.Width
};
return bt;
} /// <summary>
/// 按最简单的来,DataGrid对应的应该是有几个column创建几个TablixMember
/// </summary>
private TablixHierarchyType CreateTablixColumnHierarchy()
{
return new TablixHierarchyType() { Items = new object[] { CreateTablixColumnMembers() } };
} private TablixMembersType CreateTablixColumnMembers()
{
TablixMembersType tmts = new TablixMembersType();
tmts.TablixMember = new TablixMemberType[HeaderNames.Count];
EnumHeaderNames(p =>
{
tmts.TablixMember[p] = CreateTablixColumnMember();
});
return tmts;
} // DataGrid的Column对应的TablixMember创建一个空的就行
private TablixMemberType CreateTablixColumnMember()
{
return new TablixMemberType();
} // DataGrid按最简单的默认的来,即创建2个TablixMember即可
private TablixHierarchyType CreateTablixRowHierarchy()
{
return new TablixHierarchyType() { Items = new object[] { CreateTablixRowMembers() } };
} private TablixMembersType CreateTablixRowMembers()
{
TablixMembersType tablixMembers = new TablixMembersType();
tablixMembers.TablixMember = new TablixMemberType[]
{
CreateTablixRowMember0(),
CreateTablixRowMember1(),
};
return tablixMembers;
} private TablixMemberType CreateTablixRowMember0()
{
TablixMemberType tmt = new TablixMemberType(); tmt.Items = new object[]
{
CreateTablixRowMemberKeepWithGroup(),
true,
};
tmt.ItemsElementName = new ItemsChoiceType72[]
{
ItemsChoiceType72.KeepWithGroup,
ItemsChoiceType72.RepeatOnNewPage,
}; return tmt;
} private TablixMemberTypeKeepWithGroup CreateTablixRowMemberKeepWithGroup()
{
return TablixMemberTypeKeepWithGroup.After;
} private TablixMemberType CreateTablixRowMember1()
{
TablixMemberType tmt = new TablixMemberType();
tmt.Items = new object[] { CreateTablixRowMemberGroup() };
tmt.ItemsElementName = new ItemsChoiceType72[] { ItemsChoiceType72.Group };
return tmt;
} private GroupType CreateTablixRowMemberGroup()
{
return new GroupType() { Name = "详细信息" };
} /// <summary>
/// ReportDataSource.Name和RDLC文件的DataSetNamey应保持一致
/// 对于DataGrid构造的报表,可统一固定用"CustormerDataSet";
/// DataSetName不需要作为参数传进来
/// </summary>
/// <returns>DataSet Name</returns>
private string CreateDataSetName()
{
return String.IsNullOrEmpty(DataSetName) ? "CustomerDataSet" : DataSetName;
} private StyleType CreateTablixStyle()
{
StyleType st = new StyleType();
st.Items = new object[] { CreateTablixBorder() };
st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.Border };
return st;
} // Tablix的外边框格式
private BorderType CreateTablixBorder()
{
BorderType bt = new BorderType(); bt.Items = new object[]
{
"Black",
"Solid",
"2pt"
};
bt.ItemsElementName = new ItemsChoiceType2[]
{
ItemsChoiceType2.Color,
ItemsChoiceType2.Style,
ItemsChoiceType2.Width
}; return bt;
} #endregion
}

TablixRdlcGenerator.cscs

第三步:提取DataGrid的数据

1、主要从DataGrid提取每个Column的Width、BindingPath、Header的Content和每个单元格的数据。数据填充DataTable的Rows, BindingPath填充DataTable的Columns,

Header的Content用来作为报表Tablix的标题行。BindingPath,对于DataTemplate和DataGridHyperlinkColumn不知道咋个取提取数据.

2、dataGrid.ScrollIntoView(dataGrid.Items[rowIndex])这个是关键。DataGrid用了一个虚拟啥子来着的(名字不重要,原理简单,计算机领域大量处理性能的都是用这个办法),就是复用界面显示,一个窗口里能装下的几十条RowContainer,每次滚动,人要看到的时候才重新提取新的要显示的数据。

这样提取数万条记录时,界面不会卡,也不会占用很多内存,每次是要显示的时候才取几十条,一点点取。要用,才给,只给需要的那点。

      /// <summary>
/// DataGrid的转换器,从DataGrid里提取出数据源,以及HeaderName、Binding的Path和ActualWidth
/// </summary>
/// <param name="dataGrid">包含数据的DatGrid</param>
/// <param name="dt">DataGrid数据源转换成的DataTable</param>
/// <param name="headerNames">DataGridColumn.Header</param>
/// <param name="bindingPaths"> DataGridBoundColumn.Binding.Path</param>
public static void DataGridAdapter(this DataGrid dataGrid, DataTable dt, List<string> headerNames, List<string> bindingPaths, List<double> widths)
{
// 取出DataGridColumn的Header,BingdingPath,ActualWidth为构造rdlc文件准备数据
headerNames.Clear();
bindingPaths.Clear();
widths.Clear();
for (int index = ; index < dataGrid.Columns.Count; index++)
{
headerNames.Add(dataGrid.Columns[index].Header as string);
widths.Add(dataGrid.Columns[index].ActualWidth);
//string tempBindingPath = ((dataGrid.Columns[index] as DataGridBoundColumn).Binding as Binding).Path.Path;
string tempBindingPath = GetDataGridColumnBindingPath(dataGrid.Columns[index]);
bindingPaths.Add(tempBindingPath); if (String.IsNullOrEmpty(tempBindingPath) == false)
dt.Columns.Add(tempBindingPath, typeof(string));
} for (int rowIndex = ; rowIndex < dataGrid.Items.Count; rowIndex++)
{
// 要显示后,才能取到数据
DataGridRow rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
// 因为Peformance问题,EnableRowVirtualization被设置为true,只加载要显示的数据
// 重新滚动,然后再重用这些DataGridRow
if (rowContainer == null)
{
dataGrid.UpdateLayout();
dataGrid.ScrollIntoView(dataGrid.Items[rowIndex]);
rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
}
if (rowContainer != null)
{
DataGridCellsPresenter presenter = DataGridHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter != null)
{
DataRow dr = dt.NewRow();
bool isLastRowAllEmpty = true;
for (int columnIndex = ; columnIndex < bindingPaths.Count; columnIndex++)
{
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
if (cell != null)
{
if (cell.Content is TextBlock)
{
//TODO: DataGridHyperlinkColumn取不到数据
dr[bindingPaths[columnIndex]] = (cell.Content as TextBlock).Text;
if (!String.IsNullOrEmpty((cell.Content as TextBlock).Text)) isLastRowAllEmpty = false;
}
else if (cell.Content is CheckBox)
{
string value = ((cell.Content as CheckBox).IsChecked == true) ? "是" : "否";
dr[bindingPaths[columnIndex]] = value;
}
else if (cell.Content is ComboBox)
{
dr[bindingPaths[columnIndex]] = (cell.Content as ComboBox).Text;
if (!String.IsNullOrEmpty((cell.Content as ComboBox).Text)) isLastRowAllEmpty = false;
}
}
} if (dataGrid.CanUserAddRows && (rowIndex == dataGrid.Items.Count - ))
{
// 如果CanUserAddRows被设置为true,只有最后一行的数据都不为空(CheckBox不算作内),才把数据添加到DataTable
if (isLastRowAllEmpty)
{
continue;
}
}
dt.Rows.Add(dr);
}
}
}
}

提取DataGrid数据

第四步:填充数据

关键在设置ReportViewer类的LocalReport.ReportPath 和LocalReport.DataSources这两项。

        /// <summary>
/// 报表数据源发生变化时,及时更新显示报表控件的数据源
/// </summary>
/// <param name="reportDataModel">报表数据模型基类</param>
public void ResetReportData(ReportDataModel reportDataModel)
{
if (reportDataModel != null)
{
reportViewer.Reset();
reportViewer.LocalReport.DataSources.Clear();
reportViewer.Clear(); if (!reportDataModel.IsDataGrid)
reportViewer.LocalReport.ReportPath = reportDataModel.RDLCReportPath;
else
{
// 如果是DataGrid转换成的,直接从内存流里加载数据
if (reportDataModel.MsDataGrid != null)
{
reportViewer.LocalReport.LoadReportDefinition(reportDataModel.MsDataGrid);
// 用完就释放掉,流所占用的所有资源
// reportDataModel.MsDataGrid.Dispose();
}
}
reportViewer.LocalReport.DataSources.Add(reportDataModel.ReportDataSource);
reportViewer.RefreshReport();
}
}

ResetReportData

第五步:提供一个ReportHelper类

具体拼接数据以及计算高度等,还有用另一套办法实现第二个功能。

1、根据DataGrid每列的宽度,按百分比,重新设置每列的宽度。

         /// <summary>
/// 根据DataGrid的Column的Actual Width来设置报表里对应Tablix的TablixColumn的宽度
/// </summary>
/// <param name="reportWidth">报表的总宽度</param>
/// <param name="widths">DataGrid的Column的Actual Width</param>
/// <param name="tablixColumnWidths">重新按百分比计算的TablixColumn的宽度列表</param>
public static void CalcTablixColumnWidth(string reportWidth, List<double> widths, out List<string> tablixColumnWidths)
{
double totalWidth = 0.0;
double originalTotalWidth = 0.0;
List<double> rateColumnWidth = new List<double>();
string unit = reportWidth.Substring(reportWidth.Length - , ); // 取到报表宽度字符串除去单位in或者cm的数值
Double.TryParse(reportWidth.Substring(, reportWidth.Length - ), out totalWidth); for (int index = ; index < widths.Count; index++)
originalTotalWidth += widths[index]; for (int index = ; index < widths.Count; index++)
rateColumnWidth.Add(widths[index] / originalTotalWidth); tablixColumnWidths = new List<string>();
tablixColumnWidths.Clear();
for (int index = ; index < widths.Count; index++)
tablixColumnWidths.Add((rateColumnWidth[index] * totalWidth).ToString() + unit);
}

CalcTablixColumnWidth

2、把内存中的流读出来,生成对应的RDLC文件,我那里没调用。所以设置LocalReport.ReportPath换成reportViewer.LocalReport.LoadReportDefinition(reportDataModel.MsDataGrid);

         /// <summary>
/// 把内存的流生成为rdlc文件
/// </summary>
/// <param name="rdlc">按rdlc格式构造成功的内存流</param>
public static void DumpRdlc(MemoryStream rdlc)
{
string tempRdlcPath = AppDomain.CurrentDomain.BaseDirectory + @"../../../CommonReport/Templates/GeneratedDataGrid.rdlc";
if (File.Exists(tempRdlcPath))
File.Delete(tempRdlcPath); using (FileStream fs = new FileStream(tempRdlcPath, FileMode.Create))
{
rdlc.WriteTo(fs);
}
}

DumpRdlc

3、部分调用的代码——给一个简单的RDLC模板,以提供表头的字体格式和表内部数据等样式相关的信息,然后再用DataGrid里提取的数据,填充到报表里

         /// <summary>
/// 将DataGrid的数据抽取出来,转换成rdlc报表,以实现对提供DataGrid的打印、预览、分页和页面布局等功能的支持
/// 但需要提供一个rdlc报表的模板,必须包括页眉页脚,至少一列数据和标题,以便拿到数据的表头的
/// style和数据项的style,这一列数据项必须是第一项(且第一项的表头和数据都完整提供了style)
/// </summary>
/// <param name="dataGrid">提供数据的DataGrid</param>
/// <param name="reportViewer">要加载DataGrid数据的ReportViewer</param>
/// <param name="rdlcModelFileName">rdlc模板的完整路径</param>
/// <param name="headline">报表标题</param>
public static void Print(this DataGrid dataGrid, CommonReport.Views.ReportViewer reportViewer, string rdlcModelFileName, string headline)
{
if (!File.Exists(rdlcModelFileName)) return; // 从DataGrid对应的rdlc模板里读出报表数据来
Report report = null;
string dataSourceName = DatasetName;
dataGrid.UnderRdlcGenProc(reportViewer, headline, gen =>
{
report = gen.Read(rdlcModelFileName); // ReportDataSource的Name应该用取DataSet的Name
#region 取DataSourceName DataGridHelper.ResetRdlcHeadline(report, headline);
for (int index = ; index < report.Items.Length; index++)
{
if (report.Items[index] is DataSetsType)
{
DataSetsType dataSets = report.Items[index] as DataSetsType;
dataSourceName = dataSets.DataSet[].Name;
break;
}
} #endregion
}, (gen, ms, dt) =>
{
// 根据从DataGrid里提取的数据重新构造rdlc文件
RdlcReportAdapter(report, gen.HeaderNames, gen.FieldNames, gen.Widths);
gen.Write(ms, report);
return new Microsoft.Reporting.WinForms.ReportDataSource(dataSourceName) { Value = dt };
});
}

Print

4、打印的关于页面的一些默认设置(看情况)

             // 设置默认打印布局模式为“显示物理页”
reportViewer.SetDisplayMode(DisplayMode.PrintLayout);
reportViewer.ZoomMode = ZoomMode.Percent;
reportViewer.ZoomPercent = ;

打印设置

5、TreeView反射那块——功能三

         /// <summary>
/// TreeView上选择的项发生变化时,根据所选TreeViewItem的Header信息和Tag里所存储的信息,利用反射构造对应报表的数据类实例
/// 加载报表模板,调用委托将数据传到报表的显示控件上
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RdlcTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if ((sender != null) && (sender is TreeView))
{
if ((sender as TreeView).SelectedItem is TreeViewItem)
{
TreeViewItem tempItem = (sender as TreeView).SelectedItem as TreeViewItem;
if (tempItem.Tag is TreeViewItemDataType)
{
TreeViewItemDataType tempTreeViewDataType = tempItem.Tag as TreeViewItemDataType;
// 报表类型
if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.Report)
{
string reportDataModelInstanceName = tempItem.Header + "Model";
Type type = typeof(ReportDataModel);
Assembly assembly = type.Assembly;
try
{
ReportDataModel reportDataModelInstance = (ReportDataModel)assembly.CreateInstance(type.Namespace + "." + reportDataModelInstanceName);
if (reportDataModelInstance != null)
{
reportDataModelInstance.RDLCReportPath = (tempItem.Tag as TreeViewItemDataType).FullPath;
reportDataModelInstance.InitDataSource();
if (Viewer != null)
Viewer.ResetReportData(reportDataModelInstance);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} // DataGrid 类型
else if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.DataGrid)
{
Type type = this.GetType();
Assembly assembly = type.Assembly;
try
{
UserControl dataGridUserControlInstance = (UserControl)assembly.CreateInstance(type.Namespace + ".DataGrid." + tempItem.Header);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
}

RdlcTree_SelectedItemChanged

6、通过VisualTreeHelper找到指定类型的子或者父的方法,可在WPF里通用

        /// <summary>
/// 找出子Visual的特定类型的Parent
/// </summary>
/// <typeparam name="T">指定类型</typeparam>
/// <param name="child">继承自Visual的基本控件类型的子Visual</param>
/// <returns></returns>
public static T GetParent<T>(Visual child) where T : Visual
{
T parent = default(T);
Visual visual = VisualTreeHelper.GetParent(child) as Visual;
parent = visual as T;
if (parent == null)
return GetParent<T>(visual);
else
return parent;
} /// <summary>
/// 遍历取父控件的子Viusal,取到指定类型的子Viusal
/// </summary>
/// <typeparam name="T">T是Visual或其子类(基本上WPF的控件都是Visual的子类),指定子类型</typeparam>
/// <param name="parent">父控件</param>
/// <returns>子Viusal</returns>
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = ; i < numVisuals; i++)
{
Visual visual = (Visual)VisualTreeHelper.GetChild(parent, i);
child = visual as T;
if (child == null)
child = GetVisualChild<T>(visual);
else
break;
}
return child;
}

VisualTreeHelper

7、提供一个数据深拷贝的通用方法(C#类以及除基类型之外,好多都是传引用,这个是地址,值拷贝不好搞,这个方法直接拷贝流,但是必须类的每个字段都支持序列化)

         /// <summary>
/// 对引用类型的数据——“所有字段都加了Serializable特性,以支持序列化”
/// 利用序列化和反序列化实现深度拷贝,即拷贝了堆上的数据,搞了个堆的副本
/// 而不是浅拷贝那样,只是拷贝了一个指向数据堆的内存地址
/// 非常实用的小函数,支持所有引用类型数据
/// </summary>
/// <param name="original">要拷贝的引用类型数据源</param>
/// <returns>源数据的副本</returns>
public static object DeepColne(Object original)
{
// 构造一个临时的内存流
using (MemoryStream ms = new MemoryStream())
{
// 调用BinaryFormatter来完成复杂的序列化和反序列化工作
BinaryFormatter formatter = new BinaryFormatter(); // StreamingContext—描述给定的序列化流的源和目标,并提供一个由调用方定义的附加上下文
formatter.Context = new StreamingContext(StreamingContextStates.Clone); // 把对象图序列化到内存流,original的每个字段必须标记为可序列化,否则会出错
formatter.Serialize(ms, original); // 反序列化之前需要设置流的当前位置为最开始的位置
ms.Position = ; // 把内存流反序列化为对象图,再以基类的形式返回给调用者
return formatter.Deserialize(ms);
}
}

DeepColne

六、运行效果

1、含有DataGrid或者其它控件的界面

动态生成RDLC报表

2、点击打印后,报表生成

动态生成RDLC报表

附:

1、ReportItems!具体RDLC报表上控件的名称.Value这个取到报表设计器里任意项的数据,然后就可在表达式里进行各种逻辑运算。例如:

= ReportItems!forestryMaintenance.Value + ReportItems!pension.Value + ReportItems!SumPolicy.Value
+ ReportItems!livingExpenses.Value + ReportItems!resettlement.Value

2、合并单元格,纵向和横向的

这个要分组,具体请搜索网上资源

3、控制每页都显示

对于标题,设置KeepWith属性和Tablix一起出现就好;还有一个办法,是设置其它的属性,暂时忘了,网上有

4、XML很重要,据目前所知,微软的工程文件、WPF、打印、报表、XPS、Office2007以后版本等,XML都是基石。(未完,待续)

5、页面纸张尺寸(PageSetting里的一些关于大小的值,单位都是1/100 inch;页面设置布局排版打印有点麻烦,稍不注意就多出去一点,字体、页眉、页脚、边框、页边距等),如下图:

动态生成RDLC报表

6、border style

动态生成RDLC报表

末了,必须感谢和致敬蜡人张前辈:

http://waxdoll.cnblogs.com/archive/2006/02/25/337713.html

2.微软GotReportViewer官方的案例:

http://www.gotreportviewer.com/(约有20来个,很详细。有时候会上不了)

动态生成RDLC报表的更多相关文章

  1. 分享一个动态生成RDLC报表的类

    在实际工作中,当需要进行大批量查询和生成报表的时候,可以使用我写的类. 特点: 无需报表设计器.无需为报表设置数据集 只需要传入查询结果就可以全自动生成报表,传入的对象为Dynamic(目前支持Dat ...

  2. &lbrack;转&rsqb;简单的动态修改RDLC报表页边距和列宽的方法

    本文转自:http://star704983.blog.163.com/blog/static/136661264201161604413204/ 1.修改页边距 XmlDocument XMLDoc ...

  3. WPF &plus; RDLC &plus; 动态生成列 &plus; 表头合并

    如下,评论超过20条,马上发代码*(੭*ˊᵕˋ)੭*ଘ,效果如下: 代码逻辑简单. WPF使用RDLC需要使用如下DLL 新建WPF 窗体,黏贴下大概如下 <Window xmlns:rv=&q ...

  4. 利用General框架开发RDLC报表

    RDLC是微软推出的自家的报表软件,虽然没有一些第三方的报表软件强大好用,但是作为VisualStudio集成的报表工具,在客户要求不高的情况下还是非常值得一用的,本文将介绍通过General代码生成 ...

  5. Asp&period;net Report动态生成

    rdlc报表实质上是一个xml文件,如果要实现动态报表,就需要动态生成rdlc文件,实质上就是读写xml文件: protected XmlDocument GenerationAddReportCol ...

  6. &lbrack;转&rsqb;RDLC报表——动态添加列

    本文转自:http://www.cnblogs.com/pszw/archive/2012/07/19/2599937.html 前言 最近接到一个需求:在给定的数据源中,某(些)列,可能需要单独统计 ...

  7. 会员管理系统的设计和开发(2)-- RDLC报表的设计及动态加载

    在上篇<会员管理系统的设计和开发(1)>介绍了关于会员系统的一些总体设计思路和要点,经过一段时间开发,软件终于完成并发布.在这期间,碰到了不少技术难点,并积累了不少开发心得和经验,本篇继续 ...

  8. RDLC报表系列&lpar;一&rpar; 简单的动态数据绑定和配置

    RDLC系列链接 RDLC报表系列(一) 简单的动态数据绑定和配置  RDLC报表系列(二) 行分组 RDLC报表系列(三) 总计和折叠 RDLC报表系列(四) 矩阵 RDLC报表系列(五) 简单的图 ...

  9. C&num; WinfForm 控件之dev报表 XtraReport (八)动态生成报表

    功能说明:生成一个报表文件DV1,保存到本地AA.rep,再重新加载这个文件到DV2 1.布局如下图: panel1 上有三个button panel2上有个documentView dv1 pane ...

随机推荐

  1. AI&lpar;一&rpar;:概念与资讯

    AI: Artificial Intelligence(人工智能),它是研究.开发用于模拟和扩展人的智能的理论.方法.技术及应用系统的一门新的技术科学,上个世纪50年代一次学术讨论会议上,下图中几位著 ...

  2. DSP&lpar;2&rpar; -- 离散时间信号的序列运算

    1.信号相加:这是一种对应的样本与样本之间的相加. 在Matlab中它可用算术运算符“+”实现,然后x1和x2的长度必须相等.如果序列不等,或者长度虽然相等但采样的位置不同,就不能用运算符“+”了.我 ...

  3. git学习笔记06-创建分支合并分支-比svn快多了,因为只有指针在改变

    一开始git只有一条时间线,这个分支叫主分支,即master分支. HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支. 每次提交,mas ...

  4. dedecms 调用channel子栏目的id问题

    dedecms 说明文档:http://www.dedecms.com/archives/templethelp/help/taghelp.htm {dede:channel type='son' t ...

  5. MySQL中DATE&lowbar;FORMATE函数内置字符集解析

    今天帮同事处理一个SQL(简化过后的)执行报错: 代码如下 复制代码 mysql> select date_format('2013-11-19','Y-m-d') > timediff( ...

  6. LeetCode 61

    Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. For exa ...

  7. 使用PHP抓取网站ico图标

    网站许久没用更新,以后会经常更新,本次分享一个使用PHP抓取网站ico的程序,提供一个网站列表后对网站的ico进行下载抓取,具体代码如下: <?php /** * 更新热站ico * gao 2 ...

  8. SIM900A设备在保加利亚无法正常使用GPRS问题

    1.      SIM900A设备在保加利亚GPRS功能无法正常使用 我们一款手持设备采用SIM900A模块,在发货之前测试正常,但到了保加利亚,客户发现无法正常上网,我们技术支持反馈的邮件反馈的现象 ...

  9. Luogu 1098 - 字符串的展开 - &lbrack;字符串操作&rsqb;&lbrack;模拟&rsqb;

    题目链接:https://www.luogu.org/problemnew/show/P1098 题目描述在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中 ...

  10. alter日志报WARNING&colon; too many parse errors

    数据库版本:12.2.0 操作系统版本:RHEL7.2 最近观察到一个数据库alert日志老是报硬解析太多错误,且对应的sql语句都是查看数据字典表: 2017-06-16T08:46:46.4174 ...