注:此文本人是用Windows Live Writer 离线写的,没想到发布到CSDN后格式完全变了! 晕! 如有疑问的请联系. 另现求源代码的朋友不好意思了, 这个组件现在是商业软件的一部分, 恕不能提供.
动态报表DLL名: DynamicReportBuilder
类成员:
主框架:
目的:
完全实现Excel的丰富动态报表功能! 不再需要内置报表模板到程序.
开发语言: C#
引用组件:
- ActiveReports 3;
- 为了广泛支持更多的网格视图控件,本项目未引用除ActiveReports以外的任何第三方组件。
功能描述:
- 支持由任何数据结构对象(如:DataGridView; DevExpress.GridControl,DataTable...)构建报头字段;
- 支持自定义报表标题(TitleText),子标题(SubTitleText);
- 支持自定义分组(GroupHeader),并实现分组层级(GroupLevel).支持分组段尾(GroupFooter),页脚统计(PageFooter);
- 支持自定义字段的位置排序、字段标头宽度、颜色等设置;
- 动态报表中的各列(ReportField)自动匹配纸张宽度;
- 支持动态报表条件样式(FormatsCondition), 现在可以在报表预览窗口自定义创建条件样式了(v1.1)!
- 支持自定义打印机页面设置,字体,
- 支持ParentBanded固定带宽栏;
- 支持另存为项目模板文件。
- 已实现主从表的动态报表, 并提供了自己实现的表头数据源设计器(v1.1);
待完善:
- 目前调整字段顺序的方式为:双击字段项向下,按下CTRL键双击字段项则向上。这种功能是常用的,但目前没有提供比较好的显式操作方式,故需再改进报表配置器UI。
动态报表配置器主界面(失真的GIF动画):
源代码:
using System;
using System.Drawing;
using System.Text;
namespace CIMS.Report.Center.Builder
{
public class ReportField:IDisposable
{
protected ReportFieldCollectionBase m_collection = null;
protected FieldAppearance m_appearance = null;
protected FieldBehavior m_behavior = null;
protected string m_caption = string.Empty;
protected string m_dataField = string.Empty;
protected Type m_dataType;
protected float m_width = 0;
protected string m_outputFormat = string.Empty;
protected object m_tag = null;
protected int m_index = 0;
protected bool m_visible = true;
protected ReportField m_banded = null;
public event EventHandler FieldVisibleChanged = null;
public event EventHandler FieldCaptionChanged = null;
public event EventHandler FieldWidthChanged = null;
public event FieldIndexChangedHandler FieldIndexChanged = null;
public ReportField(ReportFieldCollectionBase collection) : this(collection, string.Empty, string.Empty, 0, true) { }
public ReportField(ReportFieldCollectionBase collection, string dataField) : this(collection, dataField, dataField, 0, true) { }
public ReportField(ReportFieldCollectionBase collection, string caption, string dataField) : this(collection, caption, dataField, 0, true) { }
public ReportField(ReportFieldCollectionBase collection, string caption, string dataField, float width) : this(collection,caption, dataField, width, true) { }
public ReportField(ReportFieldCollectionBase collection, string caption, string dataField, float width, bool visible)
{
m_collection = collection;
m_caption = caption;
m_dataField = dataField;
m_width = width;
m_visible = visible;
m_appearance = new FieldAppearance();
m_behavior = new FieldBehavior();
}
#region Properties
/// <summary>
/// 获取当前字段的集合
/// </summary>
public ReportFieldCollectionBase Collection { get { return m_collection; } }
/// <summary>
/// 获取或设置 当前字段的所属固定带(没有即为Nothing)
/// </summary>
public ReportField ParentBanded { get { return m_banded; } set { m_banded = value; } }
/// <summary>
/// 获取列效果设置对象
/// </summary>
public FieldAppearance Appearance { get { return m_appearance; } }
/// <summary>
/// 获取列行为设置对象
/// </summary>
public FieldBehavior Behavior { get { return m_behavior; } }
/// <summary>
/// 获取或设置行标题文本
/// </summary>
public string Caption { get { return m_caption; } set { if (m_caption == value)return;
m_caption = value;
if (FieldCaptionChanged != null && this.IsLock == false) FieldCaptionChanged(this, EventArgs.Empty);
} }
protected bool IsLock { get {
if (m_collection is ReportFieldCollection) return ((ReportFieldCollection)this.Collection).IsLock;
return false;
} }
/// <summary>
/// 获取或设置绑定到报表控件的数据字段名
/// </summary>
public string DataField { get { return m_dataField; } set { m_dataField = value; } }
/// <summary>
/// 获取或设置绑定字段的数据类型.在生成报表时,根据此类型属性决定创建合适的控件类型
/// </summary>
public Type DataType { get { return m_dataType; } set { m_dataType = value; } }
/// <summary>
/// 获取或设置列的初始宽度
/// </summary>
public float Width { get { if (this.Visible == false)return 0; return m_width; } set {
if (m_width == value) return;
m_width = value;
if (FieldWidthChanged != null && this.IsLock==false) FieldWidthChanged(this, EventArgs.Empty);
} }
/// <summary>
/// 获取或设置列输出文本的格式化字符格式
/// </summary>
public string OutputFormat { get { return m_outputFormat; } set { m_outputFormat = value; } }
/// <summary>
/// 获取或设置列的用户数据对象
/// </summary>
public object Tag { get { return m_tag; } set { m_tag = value; } }
/// <summary>
/// 获取或设置位置索引
/// </summary>
public int Index
{
get { if (this.Visible == false)return -1; return m_index; }
set
{
if (m_index == value) return;
int oldIndex=m_index;
m_index = value;
if (FieldIndexChanged != null && this.IsLock == false) FieldIndexChanged(this, new FieldIndexChangedArgs(m_index, oldIndex));
}
}
/// <summary>
/// 获取或设置是否创建到报表对象(在报表中是否可见)
/// </summary>
public bool Visible
{
get { return m_visible; }
set
{
if (m_visible == value) return;
m_visible = value;
if (FieldVisibleChanged != null && this.IsLock == false) FieldVisibleChanged(this, EventArgs.Empty);
}
}
#endregion
public override bool Equals(object obj)
{
if (obj is ReportField) return ((ReportField)obj).DataField == this.DataField;
if (obj != null) return obj.ToString() == this.ToString();
return base.Equals(obj);
}
public override string ToString()
{
return this.DataField;
}
#region IDisposable 成员
public void Dispose()
{
this.Appearance.Dispose();
}
#endregion
}
}
……由于源代码太多! 下面只贴核心代码.
下面是配置器UI的核心代码…
下面是动态报表的核心实现部分(ReportBuilderBase,ReportBuilder,DetailReportBuilder待实现 )…
我们先来了解一下纸张布局.
- 用于装订的装订线边距(固定区域);
- 上边距区域(相当于页眉);
- 打印区域(可通过调整页边距来打印更多内容!);
- 左右对开页的对称页边距;
- 下边距区域(相当于页脚)。
- 动态报表需要使各列按纸张打印区域自动调整宽度缩放比例,以不能产生空白区域或超出打印区域。下面是关键属性/函数:
- 由于ActiveReports默认使用的是英制单位,所以我们需要知道:1英寸=1/100像素。
///
/// 可放置控件的总宽度
///
protected float PrintWidth { get { return m_printWidth; } }
///
/// 控件的宽度缩放比例
///
protected float PrintWidthScale { get { return m_printWidthScale; } }
m_printWidth 和 m_printWidthScale 变量在BeginBuild(ActiveReport3 rpt)方法中初始化:
protected
virtual
void
BeginBuild(ActiveReport3 rpt)
{
//......更多初始化代码
m_defaultHeight = DesignOptions.DefaultPageDetailByNewReport;
m_hasBandeds = this
.Fields.HasBandedColumns;
m_printWidth = RoundTowDecimals(Settings.CalcPaperValidWidth(rpt.PageSettings));//打印空间宽度
if
(m_printWidth == -1) m_printWidth = DesignOptions.DefaultPrintWidthByNewReport;//默认宽度
m_printWidthScale = this
.Settings.AutoScaleFieldsSizeByPaperSpace ? CalcSacleWidth(m_printWidth) : 1;
}
protected
SizeF GetFieldSize(ReportField field, bool
fixFieldHeight)
{
return
GetFieldSize(field, fixFieldHeight, this
.DefaultHeight);
}
protected
SizeF GetFieldSize(ReportField field, float
customHeight)
{
return
GetFieldSize(field, false
, customHeight);
}
protected
SizeF GetFieldSize(ReportField field, bool
fixFieldHeight,float
fixHeight)
{
return
new
SizeF(RoundTowDecimals(CalcInchByFontSize(field.Width) * PrintWidthScale), fixFieldHeight ? fixHeight : (this
.HasBandeds && field.ParentBanded == null
? fixHeight * 2 : fixHeight));
}
///
/// 按文本和字体获取控件的大小,不适合于字段
///
///
文本
///
字体
///
是否返回字体高度,否则返回默认高度
///
protected
SizeF GetSize(string
text, Font font, bool
customHeight)
{
Graphics g = Owner.CreateGraphics();
using
(g)
{
SizeF result = g.MeasureString(text, font);
return
new
SizeF(RoundTowDecimals(CalcInchByFontSize(result.Width) * PrintWidthScale), (customHeight ? ConvertToInch(result.Height) : this
.DefaultHeight));
}
}
///
/// 计算固定带宽的总宽度
///
///
字段的固定带宽
///
public
SizeF GetBandedSize(ReportField banded)
{
float
totalWidth = 0;
foreach
(ReportField field in
this
.Fields)
{
if
(field.ParentBanded.Equals(banded)) totalWidth += GetFieldSize(field,true
).Width;
}
return
new
SizeF(totalWidth,this
.DefaultHeight);
}
public
float
CalcSacleWidth(float
printWidth)
{
float
totalWidth = 0;
foreach
(ReportField field in
this
.Fields)
{
if
(field.Visible == false
) continue
;
totalWidth += field.Width;
}
if
(Groups != null
)
{
int
count = Groups.VisibleCount;
if
(count > 1) totalWidth += (count - 1) * (DEFAULT_GROUP_LEFT * 100);
}
float
result =printWidth / ConvertToInch(totalWidth);
if
(result < 0) result = 1;
return
result;
}
public
static
float
RoundTowDecimals(float
value
)
{
return
(float
)(decimal
.Round((decimal
)value
, DEFAULT_ROUND_DECIMALS, MidpointRounding.AwayFromZero));
}
///
/// 将像素转到到英寸
///
///
像素
///
public
float
ConvertToInch(float
fieldDPI)
{
return
fieldDPI / 100;
}
///
/// 计算字段的实际宽度(英寸,不应用缩放比例)
///
///
像素
///
protected
float
CalcInchByFontSize(float
fieldDPI)
{
float
inchWidth = ConvertToInch(fieldDPI );
float
multiple = 0;
if
(this
.Settings.ReportFont.Size >= 11) multiple = 0.5f;
else
if
(this
.Settings.ReportFont.Size >= 10) multiple = 0.2f;
else
if
(this
.Settings.ReportFont.Size >= 9) multiple = 0.1f;
return
inchWidth + (inchWidth * multiple);
}
代码太多!只贴核心方法,需要完整代码的请联系
CreateDynamicReport CoreSourceCode
带分组段落和条件格式的动态报表:
带固定带宽和条件格式及页脚统计的动态报表:
v1.1 新增功能:
1, 现在能创建主从动态报表了!
2, 新增表头数据项目设计器以更好的支持主从报表的动态创建:
3, 新增一个报表生成向导, 从UI来看, WPF技术带来的UI视觉效果果然非同一般!
4, 新增水印设计器:
v1.1 增强功能和修改:
1, 现在Form支持调整大小了!
2, 现在报表支持动态图章和水印了!