使用 XtraReports 套件,最终用户可以在 最终用户设计器 中为特定的事件处理程序编写代码,从而定制报表控件、带区或报表本身的外观。 本文档阐述了在 XtraReports 中使用脚本的基本原则,列出了使用脚本必需的主要属性,并提供了关于如何在报表中使用脚本的示例。
本文档由下列小节组成。
脚本选项
脚本是 XtraReports 的一项运行时刻功能,当在运行时刻生成报表时,允许您或最终用户执行脚本。 注意,尽管在 Visual Studio IDE 和 最终用户设计器 中都可以添加脚本,但是,此功能主要被设计用于由那些想在“最终用户设计器”中少量定制报表的高级最终用户使用。 因此,假定最终用户熟悉 XtraReports 支持的脚本语言之一: C#、Visual Basic .NET 和 JScript .NET。 在一个报表中使用的所有脚本的脚本语言必须相同,并且通过 XtraReport.ScriptLanguage 属性指定。 这也意味着脚本语言独立于创建报表的语言。
注意 |
---|
请确保在客户端支持用于报表脚本的脚本语言。 例如,在默认情况下,.NET 1.1 Framework 不支持 JScript,在执行 JScript 脚本之前,需要在最终用户机器上安装支持环境。 |
为了提供可行的报表脚本,应该正确指定另一个重要的属性 —— XtraReport.ScriptReferences (或它的运行时刻副本 —— XtraReport.ScriptReferencesString)。 此属性包含一个字符串集合,表示报表脚本所使用的程序集的路径。 注意,不 需要把下列程序集添加到 ScriptReferences 集合中:
- XtraReports 功能所需的在项目中引用的 DevExpress 程序集。 可以在 Windows 窗体部署 文档中找到这些程序集的详细列表。
- 当前已加载到应用程序域中的其他程序集;
- 始终由 XtraReports 添加的几个标准的 .NET framework 程序集: System.dll、System.Data.dll、System.Xml.dll、System.Drawing.dll、System.Windows.Forms.dll;
注意 |
---|
对于 .NET framework 程序集 (在默认情况下位于 "C:\Windows\Microsoft.NET\Framework" 路径中),只需要把文件名添加到 ScriptReferences 集合中。 |
当为最终用户启用脚本功能时,需要考虑的最后一个重要选项,是 XtraReport.ScriptSecurityPermissions。 此属性提供了允许在最终用户脚本中执行特定操作的功能。 要学习更多相关内容,请参阅 脚本的安全权限。
维护脚本
脚本是自定义事件处理程序,可以为报表及其任意元素的特定事件添加脚本 (例如 XRControl.BeforePrint 事件)。 要在最终用户设计器中这样做,则最终用户要能访问 XRControl.Scripts 集合,此集合中包含了报表控件中存在的所有事件的脚本。 注意,通过 Scripts 属性,报表及其元素都可能有唯一的事件集。 例如,只有 XRChart 控件有 XRChartScripts.OnBoundDataChanged 特殊事件。
要在设计时刻编辑报表元素的脚本属性,则展开此属性的下列列表,如果没有为此属性定义任何特定的脚本,则单击 (New) 列表项。 这样将显示 Scripts(脚本) 标签页,其中包含了以 XtraReport.ScriptLanguage 属性指定的语言编写的一个代码模板。
此标签页包含了为所有报表元素编写的全部脚本; 通过在相应的下列列表中选择所需的报表元素、并且在另一个菜单中指定可用的事件之一,就可以快速导航到脚本。
另一项值得注意的功能,是可以使用内置的脚本验证机制,通过单击 Validate(验证) 按钮来启动验证。
如果在报表脚本中检测到错误,那么这些错误被列出在脚本编辑器下方的 Scripts Errors panel(脚本错误面板) 中。 单击列表中的一条错误,则把光标移动到相应的代码段。
输入的脚本将被用于处理相应的控件事件。 以与普通事件处理程序相同的方式触发脚本事件。 在 XtraReports 中,按下列顺序执行脚本:
- XtraReports 在内存中生成临时类,并添加与报表对象、带区和控件相应的变量。 通过所表示对象的 Name 属性定义变量名。
- 预处理脚本。 在预处理期间,using 指令被从脚本代码中剪切,并添加到定义临时类的命名空间中。
- 在预处理完成之后,所有用户脚本都被作为普通文本放置在临时类的代码中。 然后,在内存中编译形成结果类,并且在需要时调用其方法来执行用户脚本。
注意 |
---|
如果对于相同的事件,报表控件有标准的事件处理方法,也有脚本方法,那么这两种方法都将被执行。 注意,在这种情况下,元素的标准事件处理方法优先于脚本方法。 |
因为被放置在临时类中的脚本代码,可以包含除去 using 指令之外的任何代码,因此,这样会出现许多种可能性: 可以声明类 (变成内部类),声明新变量、方法等。 这种方式的好处,是在一个脚本中声明的变量,可以在另一个脚本中“原样”访问,就如同临时类的变量。
脚本如何工作
下面的示例演示了脚本如何工作。 它呈现了用于接管报表细节带区事件的脚本方法 (改变表单元格的颜色),以及标签控件事件的脚本方法 (作为 自定义汇总,计算数据列的最小值)。 注意,此示例仅被设计用于测试目的 —— 可以通过 附条件的格式设置 轻易改变控件的外观,以及通过 内置汇总函数 计算最小值。
为了使本示例正确工作,应用程序应该包含一个报表对象,并把它绑定到 Northwind 数据库 (nwind.mdb 文件,位于 DevExpress 演示 的安装目录中) 的 Products 表。
这些是报表中使用的脚本:
C# | 复制代码 |
---|---|
// === Detail.Scripts.OnBeforePrint === private void OnBeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e) { XRTableCell[] cells = new XRTableCell[] { pidCell, productNameCell, productPriceCell }; System.Decimal price = (System.Decimal)GetCurrentColumnValue("UnitPrice"); if (price < 20) ChangeCellsColor(cells, Color.Red); else if (price > 60) ChangeCellsColor(cells, Color.Green); else ChangeCellsColor(cells, Color.Black); } void ChangeCellsColor(XRTableCell[] cells, Color color) { int count = cells.Length; for (int i = 0; i < count; i++) cells[i].ForeColor = color; } // === Detail.Scripts.OnBeforePrint === // === xrLabel1.Scripts.OnSummaryReset === using MyAssembly; System.Decimal minPrice = System.Decimal.MaxValue; private void OnSummaryReset(object sender, System.EventArgs e) { minPrice = System.Decimal.MaxValue; } // === xrLabel1.Scripts.OnSummaryReset === // === xrLabel1.Scripts.OnSummaryRowChanged === private void OnSummaryRowChanged(object sender, System.EventArgs e) { minPrice = Math.Min(minPrice, (System.Decimal)GetCurrentColumnValue("UnitPrice")); } // === xrLabel1.Scripts.OnSummaryRowChanged === // === xrLabel1.Scripts.OnSummaryGetResult === private void OnSummaryGetResult(object sender, SummaryGetResultEventArgs e) { e.Result = minPrice; e.Handled = true; } // === xrLabel1.Scripts.OnSummaryGetResult === |
Visual Basic | 复制代码 |
---|---|
' === Detail.Scripts.OnBeforePrint === Private Sub OnBeforePrint(sender As Object, e As System.Drawing.Printing.PrintEventArgs) Dim cells() As XRTableCell = {pidCell, productNameCell, productPriceCell} Dim price As System.Decimal = GetCurrentColumnValue("UnitPrice") If price < 20 Then ChangeCellsColor(cells, Color.Red) Else If price > 60 Then ChangeCellsColor(cells, Color.Green) Else ChangeCellsColor(cells, Color.Black) End If End If End Sub Sub ChangeCellsColor(cells() As XRTableCell, color As Color) Dim count As Integer = cells.Length Dim i As Integer For i = 0 To count - 1 cells(i).ForeColor = color Next i End Sub ' === Detail.Scripts.OnBeforePrint === ' === xrLabel1.Scripts.OnSummaryReset === Imports MyAssembly Dim minPrice As System.Decimal = System.Decimal.MaxValue Private Sub OnSummaryReset(ByVal sender As Object, ByVal e As System.EventArgs) minPrice = System.Decimal.MaxValue End Sub ' === xrLabel1.Scripts.OnSummaryReset === ' === xrLabel1.Scripts.OnSummaryRowChanged === Private Sub OnSummaryRowChanged(ByVal sender As Object, ByVal e As System.EventArgs) minPrice = Math.Min(minPrice, GetCurrentColumnValue("UnitPrice")) End Sub ' === xrLabel1.Scripts.OnSummaryRowChanged === ' === xrLabel1.Scripts.OnSummaryGetResult === Private Sub OnSummaryGetResult(ByVal sender As Object, ByVal e As SummaryGetResultEventArgs) e.Result = minPrice e.Handled = True End Sub ' === xrLabel1.Scripts.OnSummaryGetResult === |
结果代码将成为在内存中生成的一个类,并包含了下列代码。 注意,此代码仅供内部使用,并且只是演示在 XtraReports 中使用脚本的主要原则。
C# | 复制代码 |
---|---|
namespace AutogeneratedNamespace { using System; using System.Collections; using System.Drawing; using DevExpress.Data; using DevExpress.Utils; using DevExpress.XtraPrinting; using DevExpress.XtraReports; using DevExpress.XtraReports.UI; using MyAssembly; // other usings class AutogeneratedClass { private XRTableCell pidCell; private XRTableCell productNameCell; private XRTableCell productPriceCell; private XtraReport XtraReport1; // other variables private void DetailOnBeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e) { XRTableCell[] cells = new XRTableCell[] { pidCell, productNameCell, productPriceCell }; System.Decimal price = (System.Decimal)GetCurrentColumnValue("UnitPrice"); if (price < 20) ChangeCellsColor(cells, Color.Red); else if (price > 60) ChangeCellsColor(cells, Color.Green); else ChangeCellsColor(cells, Color.Black); } void ChangeCellsColor(XRTableCell[] cells, Color color) { int count = cells.Length; for (int i = 0; i < count; i++) cells[i].ForeColor = color; } System.Decimal minPrice = System.Decimal.MaxValue; private void xrLabel1OnSummaryReset(object sender, System.EventArgs e) { minPrice = System.Decimal.MaxValue; } private void xrLabel1OnSummaryRowChanged(object sender, System.EventArgs e) { minPrice = Math.Min(minPrice, (System.Decimal)GetCurrentColumnValue("UnitPrice")); } private void xrLabel1OnSummaryGetResult(object sender, SummaryGetResultEventArgs e) { e.Result = minPrice; e.Handled = true; } } } |
Visual Basic | 复制代码 |
---|---|
Namespace AutogeneratedNamespace Imports System Imports System.Collections Imports System.Drawing Imports DevExpress.Data Imports DevExpress.Utils Imports DevExpress.XtraPrinting Imports DevExpress.XtraReports Imports DevExpress.XtraReports.UI Imports MyAssembly ' other usings Class AutogeneratedClass Private pidCell As XRTableCell Private productNameCell As XRTableCell Private productPriceCell As XRTableCell Private XtraReport1 As XtraReport ' other variables Private Sub DetailOnBeforePrint(sender As Object, _ e As System.Drawing.Printing.PrintEventArgs) Dim cells() As XRTableCell = {pidCell, productNameCell, productPriceCell} Dim price As System.Decimal = GetCurrentColumnValue("UnitPrice") If price < 20 Then ChangeCellsColor(cells, Color.Red) Else If price > 60 Then ChangeCellsColor(cells, Color.Green) Else ChangeCellsColor(cells, Color.Black) End If End If End Sub Sub ChangeCellsColor(cells() As XRTableCell, color As Color) Dim count As Integer = cells.Length Dim i As Integer For i = 0 To count - 1 cells(i).ForeColor = color Next i End Sub Private minPrice As System.Decimal = System.Decimal.MaxValue Private Sub xrLabel1OnSummaryReset(ByVal sender As Object, ByVal e As System.EventArgs) minPrice = System.Decimal.MaxValue End Sub Private Sub xrLabel1OnSummaryRowChanged(ByVal sender As Object, _ ByVal e As System.EventArgs) minPrice = Math.Min(minPrice, GetCurrentColumnValue("UnitPrice")) End Sub Private Sub xrLabel1OnSummaryGetResult(ByVal sender As Object, _ ByVal e As SummaryGetResultEventArgs) e.Result = minPrice e.Handled = True End Sub End Class End Namespace |
下面的插图展示了结果报表。 注意,在运行时刻和设计时刻预览时,都会处理脚本。
重要说明
本部分包含了关于在 XtraReports 中使用脚本的其他重要说明:
-
如果完全 在运行时刻 创建报表,并且需要在其中使用脚本,那么请确保所有 报表控件 都已经指派了名称。 这是必须的,因为在 报表设计器 外部添加控件时,它们的名称还没有被定义,并且下列脚本或类似的脚本将引发异常:
C# 复制代码 XtraReport report = new XtraReport(); report.Bands.Add(new DetailBand()); report.Bands[0].Controls.Add(new XRLabel()); report.Bands[0].Controls.Add(new XRLabel()); this.ScriptsSource = "int i = 0;"; report.ShowPreviewDialog();
Visual Basic 复制代码 Dim report As New XtraReport() report.Bands.Add(New DetailBand()) report.Bands(0).Controls.Add(New XRLabel()) report.Bands(0).Controls.Add(New XRLabel()) Me.ScriptsSource = "int i = 0;" report.ShowPreviewDialog()
在这种情况下,应该使用下列代码代替:
C# 复制代码 XtraReport report = new XtraReport(); report.Bands.Add(new DetailBand()); XRLabel label1 = new XRLabel(); label1.Name = "label1"; report.Bands[0].Controls.Add(label1); XRLabel label2 = new XRLabel(); label2.Name = "label2"; report.Bands[0].Controls.Add(label2); this.ScriptsSource = "int i = 0;"; report.ShowPreviewDialog();
Visual Basic 复制代码 Dim report As New XtraReport() report.Bands.Add(New DetailBand()) Dim label1 As New XRLabel() label1.Name = "label1" report.Bands(0).Controls.Add(label1) Dim label2 As New XRLabel() label2.Name = "label2" report.Bands(0).Controls.Add(label2) Me.ScriptsSource = "int i = 0;" report.ShowPreviewDialog()