最近一个项目中,涉及到很多报表的开发,以前对水晶报表搞得比较熟,但它的庞大与其它诸多功能限制,特别是发布与部置时面临的困难,实在让人无法忍受(应该很少有人买得起正版吧),决定试一下MS Reporting Services,当然在这里只使用Local Report,对微软的Reporting Services进行了一番了解,蜡人张(http://www.cnblogs.com/waxdoll/category/49402.html)老兄这里有很多很好的学习材料,我也是从蜡人兄那里对自定义报表的研究得出以下部分修正的Demo.
对于微软提供的ReportView控件,大家都知道,不能在其中对报表的边距等进行自定义,其工具条也是根本上无法自定义控制的,每次用户打印时,都必须对页面,边距等进行调整,对用户来说,这可能是一件无法忍受的事情,这或者是为满足Reporting Services报表而这样设计的.
对蜡人张老兄提供的例子做了一些改进,主要修正以下几点:
1,修正无法使用网络打印机进行打印的问题;
2,报表使用钳入式资源加载方式;
3,提取成一用户控件ReportView,更方便于开发人员将其整合到自己的项目中
Demo文件结构:
自定义报表控件ReportView源码分如下:
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Drawing;
5using System.Data;
6using System.Text;
7using System.Windows.Forms;
8using System.IO;
9using Microsoft.Reporting.WinForms;
10namespace LocalReportDemo.Report
11{
12 public partial class ReportViewer : UserControl
13 {
14
15 private EMFStreamPrintDocument printDoc;
16
17 /// <summary>
18 /// 主报表名称
19 /// </summary>
20 private string m_ReportName = string.Empty;
21 public string ReportName
22 {
23 get
24 {
25 return this.m_ReportName;
26 }
27 set
28 {
29 this.m_ReportName = value;
30 }
31 }
32
33 /// <summary>
34 /// 主报表数据源
35 /// </summary>
36 private object m_MainDataSet = null;
37 public object MainDataSet
38 {
39 get
40 {
41 return this.m_MainDataSet;
42 }
43 set
44 {
45 this.m_MainDataSet = value;
46
47 }
48 }
49
50 /// <summary>
51 /// 主报表数据源名称
52 /// </summary>
53 private string m_MainDataSourceName = string.Empty;
54 public string MainDataSourceName
55 {
56 get
57 {
58 return this.m_MainDataSourceName;
59 }
60 set
61 {
62 this.m_MainDataSourceName = value;
63 }
64 }
65
66 /// <summary>
67 /// 钳入资源中的报表路径
68 /// </summary>
69 private string m_ReportEmbeddedResource;
70 public string MReportEmbeddedResource
71 {
72 get
73 {
74 return m_ReportEmbeddedResource;
75 }
76 set
77 {
78 m_ReportEmbeddedResource = value;
79 }
80 }
81
82 /// <summary>
83 /// 钻取报表数据源
84 /// </summary>
85 private object m_DrillDataSet = null;
86 public object DrillDataSet
87 {
88 get
89 {
90 return this.m_DrillDataSet;
91 }
92 set
93 {
94 this.m_DrillDataSet = value;
95 }
96 }
97 /// <summary>
98 /// 钻取报表数据源名称
99 /// </summary>
100 private string m_DrillDataSourceName = string.Empty;
101 public string DrillDataSourceName
102 {
103 get
104 {
105 return this.m_DrillDataSourceName;
106 }
107 set
108 {
109 this.m_DrillDataSourceName = value;
110 }
111 }
112
113 /// <summary>
114 /// 构造器
115 /// </summary>
116 public ReportViewer()
117 {
118 InitializeComponent();
119 this.Dock = System.Windows.Forms.DockStyle.Fill;
120 }
121
122 /// <summary>
123 /// 加载窗体事件
124 /// </summary>
125 /// <param name="sender"></param>
126 /// <param name="e"></param>
127 private void rpv1_Load(object sender, EventArgs e)
128 {
129 }
130 /// <summary>
131 /// 加载报表
132 /// </summary>
133 public void BindReport()
134 {
135
136 System.Type type = this.MainDataSet.GetType();
137 if (this.m_MainDataSet == null)
138 {
139 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
140 return;
141 }
142 if (type == null)
143 {
144 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
145 return;
146 }
147 else
148 {
149 System.Reflection.PropertyInfo[] picData = type.GetProperties();
150 bool bolExist = false;
151 foreach (System.Reflection.PropertyInfo piData in picData)
152 {
153 if (piData.Name == "Tables")
154 {
155 bolExist = true;
156
157 if (MainDataSourceName == string.Empty)
158 {
159 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
160 return;
161 }
162
163 this.rpv1.LocalReport.DataSources.Add(
164 new Microsoft.Reporting.WinForms.ReportDataSource(this.MainDataSourceName,
165 (piData.GetValue(this.MainDataSet, null) as System.Data.DataTableCollection)[0])
166 );
167 this.rpv1.LocalReport.ReportEmbeddedResource = this.MReportEmbeddedResource;
168 this.rpv1.RefreshReport();
169 this.lblTotal.Text = @"/" + (this.rpv1.LocalReport.GetTotalPages()+1).ToString();
170 this.tbxPage.Text = "1";
171 break;
172 }
173 }
174
175 if (!bolExist)
176 {
177 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
178 return;
179 }
180 }
181 }
182
183 工具条事件
368
369 /// <summary>
370 /// 钻取报表事件
371 /// </summary>
372 /// <param name="sender"></param>
373 /// <param name="e"></param>
374 private void rpv1_Drillthrough(object sender, DrillthroughEventArgs e)
375 {
376 if (DrillDataSet == null)
377 {
378 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
379 return;
380 }
381 else
382 {
383 if (this.DrillDataSourceName == string.Empty)
384 {
385 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
386 return;
387 }
388 else
389 {
390 Microsoft.Reporting.WinForms.LocalReport report = e.Report as Microsoft.Reporting.WinForms.LocalReport;
391 report.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource(this.DrillDataSourceName, this.GetTableCollection(this.DrillDataSet)[0]));
392 }
393 }
394 }
395 private System.Data.DataTableCollection GetTableCollection(object ReportSource)
396 {
397 System.Type type = ReportSource.GetType();
398
399 if (type == null)
400 {
401 MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
402 return null;
403 }
404 else
405 {
406 System.Reflection.PropertyInfo[] picData = type.GetProperties();
407 bool bolExist = false;
408 foreach (System.Reflection.PropertyInfo piData in picData)
409 {
410 if (piData.Name == "Tables")
411 {
412 bolExist = true;
413 return piData.GetValue(ReportSource, null) as System.Data.DataTableCollection;
414 }
415 }
416
417 if (!bolExist)
418 {
419 MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
420 return null;
421 }
422 }
423 return null;
424 }
425 }
426}
427
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Drawing;
5using System.Data;
6using System.Text;
7using System.Windows.Forms;
8using System.IO;
9using Microsoft.Reporting.WinForms;
10namespace LocalReportDemo.Report
11{
12 public partial class ReportViewer : UserControl
13 {
14
15 private EMFStreamPrintDocument printDoc;
16
17 /// <summary>
18 /// 主报表名称
19 /// </summary>
20 private string m_ReportName = string.Empty;
21 public string ReportName
22 {
23 get
24 {
25 return this.m_ReportName;
26 }
27 set
28 {
29 this.m_ReportName = value;
30 }
31 }
32
33 /// <summary>
34 /// 主报表数据源
35 /// </summary>
36 private object m_MainDataSet = null;
37 public object MainDataSet
38 {
39 get
40 {
41 return this.m_MainDataSet;
42 }
43 set
44 {
45 this.m_MainDataSet = value;
46
47 }
48 }
49
50 /// <summary>
51 /// 主报表数据源名称
52 /// </summary>
53 private string m_MainDataSourceName = string.Empty;
54 public string MainDataSourceName
55 {
56 get
57 {
58 return this.m_MainDataSourceName;
59 }
60 set
61 {
62 this.m_MainDataSourceName = value;
63 }
64 }
65
66 /// <summary>
67 /// 钳入资源中的报表路径
68 /// </summary>
69 private string m_ReportEmbeddedResource;
70 public string MReportEmbeddedResource
71 {
72 get
73 {
74 return m_ReportEmbeddedResource;
75 }
76 set
77 {
78 m_ReportEmbeddedResource = value;
79 }
80 }
81
82 /// <summary>
83 /// 钻取报表数据源
84 /// </summary>
85 private object m_DrillDataSet = null;
86 public object DrillDataSet
87 {
88 get
89 {
90 return this.m_DrillDataSet;
91 }
92 set
93 {
94 this.m_DrillDataSet = value;
95 }
96 }
97 /// <summary>
98 /// 钻取报表数据源名称
99 /// </summary>
100 private string m_DrillDataSourceName = string.Empty;
101 public string DrillDataSourceName
102 {
103 get
104 {
105 return this.m_DrillDataSourceName;
106 }
107 set
108 {
109 this.m_DrillDataSourceName = value;
110 }
111 }
112
113 /// <summary>
114 /// 构造器
115 /// </summary>
116 public ReportViewer()
117 {
118 InitializeComponent();
119 this.Dock = System.Windows.Forms.DockStyle.Fill;
120 }
121
122 /// <summary>
123 /// 加载窗体事件
124 /// </summary>
125 /// <param name="sender"></param>
126 /// <param name="e"></param>
127 private void rpv1_Load(object sender, EventArgs e)
128 {
129 }
130 /// <summary>
131 /// 加载报表
132 /// </summary>
133 public void BindReport()
134 {
135
136 System.Type type = this.MainDataSet.GetType();
137 if (this.m_MainDataSet == null)
138 {
139 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
140 return;
141 }
142 if (type == null)
143 {
144 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
145 return;
146 }
147 else
148 {
149 System.Reflection.PropertyInfo[] picData = type.GetProperties();
150 bool bolExist = false;
151 foreach (System.Reflection.PropertyInfo piData in picData)
152 {
153 if (piData.Name == "Tables")
154 {
155 bolExist = true;
156
157 if (MainDataSourceName == string.Empty)
158 {
159 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
160 return;
161 }
162
163 this.rpv1.LocalReport.DataSources.Add(
164 new Microsoft.Reporting.WinForms.ReportDataSource(this.MainDataSourceName,
165 (piData.GetValue(this.MainDataSet, null) as System.Data.DataTableCollection)[0])
166 );
167 this.rpv1.LocalReport.ReportEmbeddedResource = this.MReportEmbeddedResource;
168 this.rpv1.RefreshReport();
169 this.lblTotal.Text = @"/" + (this.rpv1.LocalReport.GetTotalPages()+1).ToString();
170 this.tbxPage.Text = "1";
171 break;
172 }
173 }
174
175 if (!bolExist)
176 {
177 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
178 return;
179 }
180 }
181 }
182
183 工具条事件
368
369 /// <summary>
370 /// 钻取报表事件
371 /// </summary>
372 /// <param name="sender"></param>
373 /// <param name="e"></param>
374 private void rpv1_Drillthrough(object sender, DrillthroughEventArgs e)
375 {
376 if (DrillDataSet == null)
377 {
378 MessageBox.Show("报表数据源不存在或为空!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
379 return;
380 }
381 else
382 {
383 if (this.DrillDataSourceName == string.Empty)
384 {
385 System.Windows.Forms.MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
386 return;
387 }
388 else
389 {
390 Microsoft.Reporting.WinForms.LocalReport report = e.Report as Microsoft.Reporting.WinForms.LocalReport;
391 report.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource(this.DrillDataSourceName, this.GetTableCollection(this.DrillDataSet)[0]));
392 }
393 }
394 }
395 private System.Data.DataTableCollection GetTableCollection(object ReportSource)
396 {
397 System.Type type = ReportSource.GetType();
398
399 if (type == null)
400 {
401 MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
402 return null;
403 }
404 else
405 {
406 System.Reflection.PropertyInfo[] picData = type.GetProperties();
407 bool bolExist = false;
408 foreach (System.Reflection.PropertyInfo piData in picData)
409 {
410 if (piData.Name == "Tables")
411 {
412 bolExist = true;
413 return piData.GetValue(ReportSource, null) as System.Data.DataTableCollection;
414 }
415 }
416
417 if (!bolExist)
418 {
419 MessageBox.Show("报表数据源格式不正确!", "提醒对话框", MessageBoxButtons.OK, MessageBoxIcon.Information);
420 return null;
421 }
422 }
423 return null;
424 }
425 }
426}
427
报表宿主窗口加载报表与数据源的方法:
1 DataSet ds = new DataSet();
2 ds.ReadXml(Application.StartupPath + @"\DataSource.xml");
3 this.reportViewer1.MainDataSet = ds;//报表主数据源
4 this.reportViewer1.MainDataSourceName = "ReportDemoDataSet_ReportDemoTable";//数据源名称
5 this.reportViewer1.MReportEmbeddedResource = "LocalReportDemo.ReportDemo.rdlc";//钳入资源的报表路径
6 this.reportViewer1.ReportName = "ReportDemo";//报表名称
7 this.reportViewer1.BindReport();//加载挷定报表
2 ds.ReadXml(Application.StartupPath + @"\DataSource.xml");
3 this.reportViewer1.MainDataSet = ds;//报表主数据源
4 this.reportViewer1.MainDataSourceName = "ReportDemoDataSet_ReportDemoTable";//数据源名称
5 this.reportViewer1.MReportEmbeddedResource = "LocalReportDemo.ReportDemo.rdlc";//钳入资源的报表路径
6 this.reportViewer1.ReportName = "ReportDemo";//报表名称
7 this.reportViewer1.BindReport();//加载挷定报表
数据源名称如下图所示:
其中钳入资源的报表路径中,LocalReportDemo为报表钳入的程序集名称
报表格式配置文件ReportSettings.xml:
1<?xml version="1.0" standalone="yes"?>
2<ReportSettings>
3 <ReportDemo>
4 <ReportName>ReportDemo</ReportName>
5 <PrinterName>Microsoft Office Document Image Writer</PrinterName>
6 <PaperName>A4</PaperName>
7 <PageWidth>21.01</PageWidth>
8 <PageHeight>29.69</PageHeight>
9 <MarginTop>0.5</MarginTop>
10 <MarginBottom>0.2</MarginBottom>
11 <MarginLeft>2.3</MarginLeft>
12 <MarginRight>0.2</MarginRight>
13 <Orientation>Z</Orientation>
14 </ReportDemo>
15</ReportSettings>
2<ReportSettings>
3 <ReportDemo>
4 <ReportName>ReportDemo</ReportName>
5 <PrinterName>Microsoft Office Document Image Writer</PrinterName>
6 <PaperName>A4</PaperName>
7 <PageWidth>21.01</PageWidth>
8 <PageHeight>29.69</PageHeight>
9 <MarginTop>0.5</MarginTop>
10 <MarginBottom>0.2</MarginBottom>
11 <MarginLeft>2.3</MarginLeft>
12 <MarginRight>0.2</MarginRight>
13 <Orientation>Z</Orientation>
14 </ReportDemo>
15</ReportSettings>
此Demo运行效果:
打印预览:
有任何问题欢迎在此提出,大家共同讨论解决
此Demo完整代码下载:
/Files/mshwu/LocalReportDemo.rar