RDLC報表之動態生成報表,rdlc報表生成
前段時間,做了RDLC報表,主要是三塊功能:
1、從DataGrid提取(包括最新的增刪改)的數據,自動生成對應的RDLC報表文件(以流的形式駐存在內存中),用ReportViewer類來展示、打印、排版、預覽、分頁
1-1、提供一個提取任意控件數據的通用接口,然後拼接成DataTable這種網狀的格子。DataGrid裡修改、增加、刪除等數據變動,立即同步更新到報表
2、給一個簡單的RDLC模板,提供表頭的字體格式和表內部數據等樣式相關的信息,然後再用DataGrid裡提取的數據,生成DataTable後其它必需信息,填充到報表裡,
自動調整報表格式
3、做了一個TreeView,很簡單;根據報表文件名稱,切換左側TreeView的Item,就加載不同的報表,顯示數據。用了一點反射的知識
第一步:根據 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多行,貼一部分,樣子參照下面代碼)
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
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關鍵就在下面的不同。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 private LocIDStringWithDataTypeAttribute CreateTablixTextRunValue(bool isHeaderCell, string name)
2 {
3 LocIDStringWithDataTypeAttribute v = new LocIDStringWithDataTypeAttribute();
4 v.Value = isHeaderCell ? name : "=Fields!" + name + ".Value";
5 v.DataType = StringWithDataTypeAttributeDataType.String;
6 return v;
7 }
CreateTablixTextRunValue
2-4、DataSet的名字一定要和ReportDataSource裡的名字完全匹配
RdlcGenerator的Read和Write方法比較重要。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
/// table + matrix = tablix
/// Microsoft 用一個tablix來支持Table(表), Matrix(矩陣) and List(列表)這三種報表項
/// 整合了table和matrix的功能
View Code
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
#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 > 0))
{
fields.Field = new FieldType[fieldNames.Count];
for (int index = 0; 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(0);
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
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
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 = 0; 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,每次滾動,人要看到的時候才重新提取新的要顯示的數據。
這樣提取數萬條記錄時,界面不會卡,也不會占用很多內存,每次是要顯示的時候才取幾十條,一點點取。要用,才給,只給需要的那點。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
/// <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 = 0; 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 = 0; 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 = 0; 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 - 1))
{
// 如果CanUserAddRows被設置為true,只有最後一行的數據都不為空(CheckBox不算作內),才把數據添加到DataTable
if (isLastRowAllEmpty)
{
continue;
}
}
dt.Rows.Add(dr);
}
}
}
}
提取DataGrid數據
第四步:填充數據
關鍵在設置ReportViewer類的LocalReport.ReportPath 和LocalReport.DataSources這兩項。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
/// <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每列的寬度,按百分比,重新設置每列的寬度。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 /// <summary>
2 /// 根據DataGrid的Column的Actual Width來設置報表裡對應Tablix的TablixColumn的寬度
3 /// </summary>
4 /// <param name="reportWidth">報表的總寬度</param>
5 /// <param name="widths">DataGrid的Column的Actual Width</param>
6 /// <param name="tablixColumnWidths">重新按百分比計算的TablixColumn的寬度列表</param>
7 public static void CalcTablixColumnWidth(string reportWidth, List<double> widths, out List<string> tablixColumnWidths)
8 {
9 double totalWidth = 0.0;
10 double originalTotalWidth = 0.0;
11 List<double> rateColumnWidth = new List<double>();
12 string unit = reportWidth.Substring(reportWidth.Length - 2, 2);
13
14 // 取到報表寬度字符串除去單位in或者cm的數值
15 Double.TryParse(reportWidth.Substring(0, reportWidth.Length - 2), out totalWidth);
16
17
18 for (int index = 0; index < widths.Count; index++)
19 originalTotalWidth += widths[index];
20
21
22 for (int index = 0; index < widths.Count; index++)
23 rateColumnWidth.Add(widths[index] / originalTotalWidth);
24
25 tablixColumnWidths = new List<string>();
26 tablixColumnWidths.Clear();
27 for (int index = 0; index < widths.Count; index++)
28 tablixColumnWidths.Add((rateColumnWidth[index] * totalWidth).ToString() + unit);
29 }
CalcTablixColumnWidth
2、把內存中的流讀出來,生成對應的RDLC文件,我那裡沒調用。所以設置LocalReport.ReportPath換成reportViewer.LocalReport.LoadReportDefinition(reportDataModel.MsDataGrid);
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 /// <summary>
2 /// 把內存的流生成為rdlc文件
3 /// </summary>
4 /// <param name="rdlc">按rdlc格式構造成功的內存流</param>
5 public static void DumpRdlc(MemoryStream rdlc)
6 {
7 string tempRdlcPath = AppDomain.CurrentDomain.BaseDirectory + @"../../../CommonReport/Templates/GeneratedDataGrid.rdlc";
8 if (File.Exists(tempRdlcPath))
9 File.Delete(tempRdlcPath);
10
11 using (FileStream fs = new FileStream(tempRdlcPath, FileMode.Create))
12 {
13 rdlc.WriteTo(fs);
14 }
15 }
DumpRdlc
3、部分調用的代碼——給一個簡單的RDLC模板,以提供表頭的字體格式和表內部數據等樣式相關的信息,然後再用DataGrid裡提取的數據,填充到報表裡
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 /// <summary>
2 /// 將DataGrid的數據抽取出來,轉換成rdlc報表,以實現對提供DataGrid的打印、預覽、分頁和頁面布局等功能的支持
3 /// 但需要提供一個rdlc報表的模板,必須包括頁眉頁腳,至少一列數據和標題,以便拿到數據的表頭的
4 /// style和數據項的style,這一列數據項必須是第一項(且第一項的表頭和數據都完整提供了style)
5 /// </summary>
6 /// <param name="dataGrid">提供數據的DataGrid</param>
7 /// <param name="reportViewer">要加載DataGrid數據的ReportViewer</param>
8 /// <param name="rdlcModelFileName">rdlc模板的完整路徑</param>
9 /// <param name="headline">報表標題</param>
10 public static void Print(this DataGrid dataGrid, CommonReport.Views.ReportViewer reportViewer, string rdlcModelFileName, string headline)
11 {
12 if (!File.Exists(rdlcModelFileName)) return;
13
14 // 從DataGrid對應的rdlc模板裡讀出報表數據來
15 Report report = null;
16 string dataSourceName = DatasetName;
17 dataGrid.UnderRdlcGenProc(reportViewer, headline, gen =>
18 {
19 report = gen.Read(rdlcModelFileName);
20
21 // ReportDataSource的Name應該用取DataSet的Name
22 #region 取DataSourceName
23
24 DataGridHelper.ResetRdlcHeadline(report, headline);
25 for (int index = 0; index < report.Items.Length; index++)
26 {
27 if (report.Items[index] is DataSetsType)
28 {
29 DataSetsType dataSets = report.Items[index] as DataSetsType;
30 dataSourceName = dataSets.DataSet[0].Name;
31 break;
32 }
33 }
34
35 #endregion
36 }, (gen, ms, dt) =>
37 {
38 // 根據從DataGrid裡提取的數據重新構造rdlc文件
39 RdlcReportAdapter(report, gen.HeaderNames, gen.FieldNames, gen.Widths);
40 gen.Write(ms, report);
41 return new Microsoft.Reporting.WinForms.ReportDataSource(dataSourceName) { Value = dt };
42 });
43 }
Print
4、打印的關於頁面的一些默認設置(看情況)
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 // 設置默認打印布局模式為“顯示物理頁”
2 reportViewer.SetDisplayMode(DisplayMode.PrintLayout);
3 reportViewer.ZoomMode = ZoomMode.Percent;
4 reportViewer.ZoomPercent = 100;
打印設置
5、TreeView反射那塊——功能三
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 /// <summary>
2 /// TreeView上選擇的項發生變化時,根據所選TreeViewItem的Header信息和Tag裡所存儲的信息,利用反射構造對應報表的數據類實例
3 /// 加載報表模板,調用委托將數據傳到報表的顯示控件上
4 /// </summary>
5 /// <param name="sender"></param>
6 /// <param name="e"></param>
7 private void RdlcTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
8 {
9 if ((sender != null) && (sender is TreeView))
10 {
11 if ((sender as TreeView).SelectedItem is TreeViewItem)
12 {
13 TreeViewItem tempItem = (sender as TreeView).SelectedItem as TreeViewItem;
14 if (tempItem.Tag is TreeViewItemDataType)
15 {
16 TreeViewItemDataType tempTreeViewDataType = tempItem.Tag as TreeViewItemDataType;
17 // 報表類型
18 if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.Report)
19 {
20 string reportDataModelInstanceName = tempItem.Header + "Model";
21 Type type = typeof(ReportDataModel);
22 Assembly assembly = type.Assembly;
23 try
24 {
25 ReportDataModel reportDataModelInstance = (ReportDataModel)assembly.CreateInstance(type.Namespace + "." + reportDataModelInstanceName);
26 if (reportDataModelInstance != null)
27 {
28 reportDataModelInstance.RDLCReportPath = (tempItem.Tag as TreeViewItemDataType).FullPath;
29 reportDataModelInstance.InitDataSource();
30 if (Viewer != null)
31 Viewer.ResetReportData(reportDataModelInstance);
32 }
33 }
34 catch (Exception ex)
35 {
36 MessageBox.Show(ex.Message);
37 }
38 }
39
40 // DataGrid 類型
41 else if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.DataGrid)
42 {
43 Type type = this.GetType();
44 Assembly assembly = type.Assembly;
45 try
46 {
47 UserControl dataGridUserControlInstance = (UserControl)assembly.CreateInstance(type.Namespace + ".DataGrid." + tempItem.Header);
48 }
49 catch (Exception ex)
50 {
51 MessageBox.Show(ex.Message);
52 }
53 }
54 }
55 }
56 }
57 }
RdlcTree_SelectedItemChanged
6、通過VisualTreeHelper找到指定類型的子或者父的方法,可在WPF裡通用
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
/// <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 = 0; 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#類以及除基類型之外,好多都是傳引用,這個是地址,值拷貝不好搞,這個方法直接拷貝流,但是必須類的每個字段都支持序列化)
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461681.gif)
![]()
1 /// <summary>
2 /// 對引用類型的數據——“所有字段都加了Serializable特性,以支持序列化”
3 /// 利用序列化和反序列化實現深度拷貝,即拷貝了堆上的數據,搞了個堆的副本
4 /// 而不是淺拷貝那樣,只是拷貝了一個指向數據堆的內存地址
5 /// 非常實用的小函數,支持所有引用類型數據
6 /// </summary>
7 /// <param name="original">要拷貝的引用類型數據源</param>
8 /// <returns>源數據的副本</returns>
9 public static object DeepColne(Object original)
10 {
11 // 構造一個臨時的內存流
12 using (MemoryStream ms = new MemoryStream())
13 {
14 // 調用BinaryFormatter來完成復雜的序列化和反序列化工作
15 BinaryFormatter formatter = new BinaryFormatter();
16
17 // StreamingContext—描述給定的序列化流的源和目標,並提供一個由調用方定義的附加上下文
18 formatter.Context = new StreamingContext(StreamingContextStates.Clone);
19
20 // 把對象圖序列化到內存流,original的每個字段必須標記為可序列化,否則會出錯
21 formatter.Serialize(ms, original);
22
23 // 反序列化之前需要設置流的當前位置為最開始的位置
24 ms.Position = 0;
25
26 // 把內存流反序列化為對象圖,再以基類的形式返回給調用者
27 return formatter.Deserialize(ms);
28 }
29 }
DeepColne
六、運行效果
1、含有DataGrid或者其它控件的界面
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461685.png)
2、點擊打印後,報表生成
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461661.png)
附:
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;頁面設置布局排版打印有點麻煩,稍不注意就多出去一點,字體、頁眉、頁腳、邊框、頁邊距等),如下圖:
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461757.png)
6、border style
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012016461763.png)
末了,必須感謝和致敬蠟人張前輩:
http://waxdoll.cnblogs.com/archive/2006/02/25/337713.html
2.微軟GotReportViewer官方的案例:
http://www.gotreportviewer.com/(約有20來個,很詳細。有時候會上不了)