你可以使用 C1FlexGrid 控件来对一个表格格式中的数据进行显示,编辑,组和总结。该表格可以绑定到一个数据源,它可以对自己的数据进行管理。
C1FlexGrid 控件有一个包含以下元素的丰富的对象模型:
以下的几个标题将引导你熟悉 C1FlexGrid 控件的几个主要特点:行与列(第 41 页)
介绍了应该如何设置表格尺寸和布局。
单元格选择(第 43 页)
介绍了"当前单元格"和"选择"的概念。
介绍了应该如何将一个单元格的集合作为一个单元来操作。
单元格图像介绍了应该如何在一个单元格中显示图像。
设置单元格格式
介绍了应该如何通过设置数字、日期和布尔值的格式,或为一个单个的单元格或一个单元格的集合改变字体、颜色、对齐方式来自定义表格的外观。
介绍了应该如何实现简单的文字编辑,下拉列表和组合列表,单元格按钮,编辑掩码和数据验证。合并单元格
介绍了应该如何通过建立"分类"意见来突出数据的关系并更改表格的显示,以便使具有类似内容的单元格合并到一起。
概述和汇总数据
介绍了应该如何将分类汇总添加到表格和如何建立一个树形大纲。
保存,加载,并打印
介绍了你应该如何对一个表格的内容或格式进行保存,并在稍后重新加载,或利用其他应用程序,例如 Microsoft Access 和 Excel,来互换表格的数据。本节还介绍了你应该如何对表格进行打印。
C1FlexGrid 属性组
介绍了一个按功能交叉引用的 C1FlexGrid 主要属性的图。
一个 C1FlexGrid 控件包括由行和列。行和列的集合受到行和列属性的影响。
当把表格绑定到一个数据源,行和列的数目取决于可用的数据源中的数据有多少。在绑定模式下,你可以使用集合的 Count 属性将它们设置为任意值。
例如,下面的代码将表格的尺寸设置为 500 行乘以 10 列:
_flex.Rows.Count = 500
_flex.Cols.Count = 10
flex.Rows.Count = 500;
_flex.Cols.Count = 10;
行和列有两个基本类型:固定的和滚动的。(通过 Count 属性被还原的数值包括了固定的和滚动的单元格)。当用户垂直滚动表格时,固定行停留在表格顶部;而当用户水平滚动表格时,固定列停留在表格左侧。
固定的单元格用于显示行和列的标题信息。
你可以通过使用行和列的集合中"固定的"属性来设置固定的行和列的数目。例如,下面的代码可以创建一个具有两个固定行和无固定列的表格:
flex.Rows.Fixed = 1
_flex.Cols.Fixed = 0
flex.Rows.Fixed = 1;
_flex.Cols.Fixed = 0;
行和列的集合也包含了在表格中插入、删除和移动行和列的方法。你可以使用"条目"属性(索引)来访问在每个集合中的独立的各个元素(行和列)。
只要你愿意,你就可以在设计时通过使用 C1FlexGrid 列编辑器来设置好表格列,而不是靠编写代码来执行这一步操作。有关如何使用 C1FlexGrid 列编辑器来对列进行编辑的更多详细信息,请参阅 C1FlexGrid 列编辑器。
"宽度"属性,或通过 C1FlexGrid 列编辑器来进行。在表格中,单击并拖动出现在列标题的右边缘的水平的双箭头可以重新调整列的尺寸。
垂直的虚线显示了表格将会如何被重新调整尺寸。向左拖动指针使列宽变小;将其向右边拖动使列宽变大。当调整的操作完成,列的"宽度"属性将被调整。
在 C1FlexGrid 列编辑器中或代码中,为列指定"宽度"属性值。有关
C1FlexGrid 列编辑器的更多详细信息,请参阅"C1FlexGrid 列编辑器"。下面的代码可以设置第一列到第十列的 "宽度"的属性:
_flex.Cols(1).Width = 10
_flex.Cols[1].Width = 10;
为了防止一个特定的列被调整,请在无论是列任务菜单上,还是列编辑器或代码中,都将这一列的"允许调整"属性设置为"假"。有关列任务菜单的更多详细信息,请参阅"列任务菜单"(第 36 页)。下面的代码可以将第一列的"允许调整"属性设置为"假":
_flex.Cols(1).AllowResizing = False
_flex.Cols[1].AllowResizing = false;
表格中有一个光标单元格,当表格时是激活的,它会显示一个焦点矩形。当表格是可编辑的,用户可以使用键盘或鼠标来移动这个光标并且编辑单元格的内容。
请注意,Office Visual Styles 也会通过高亮显示光标单元格所在的行和列标题,来显明光标单元格的位置。要想了解更多有关设置"视觉样式"的详细信息,请参阅"自定义外观,使用视觉样式"。
你可以在代码中通过使用"行与列"属性来获取或设置当前单元格。例如,将任一属性设置为-1,可以隐藏光标。
表格支持扩展选择,单元格的矩形范围由两个对立的角落决定,即光标所在单元格和单元格选择的单元格。
请注意,Office Visual Styles 也通过高亮显示选定的单元格所在的行和列的标题来显明了扩展选择的位置。要想了解更多有关设置"视觉样式"的详细信息,请参阅"自定义外观,使用视觉样式"。
你可以在代码中通过使用"行选择"和"列选择"属性来获取或设置单元格选择,或通过使用"选择"的方法也可以。注意:当光标单元格变化了,该"选择"会自动复位。要在代码中创建扩展选项,无论是通过在"行选择"和"列选择"之前先设置"行与列"或直接使用"选择"的方法都可以。
"选择"的外观是由以下属性决定的:
定焦矩形决定了焦点矩形的类型是为了表明光标单元格而绘制的。
高亮显示决定了什么时候该"选择"应该被突出显示(通常是,当该控件有一个突出的重点时,或者从不)。
高亮和定焦都是决定了"选择"的外观的单元格样式(字体,颜色和边框)。
可供选择的类型是由"选择模式"的属性决定的。在默认情况下,表格支持常规的范围选择。你可以修改此行为来防止扩展选择,或者来按行、按列,或在列表框模式下进行选择("列表框模式"可以允许你来选择个别行)。
当使用列表框选择模式时,你可以通过使用"选择"属性来获取或设置个别行的选择状态。你还可以通过使用"选择"属性来恢复选定的行的集合。例如,下面的代码可以选择符合一个条件的所有行:
' 在"销售"列中选择多于 8000 名销售的所有行。
_flex.SelectionMode = C1.Win.C1FlexGrid.SelectionModeEnum.ListBox
Dim index As Integer
For index = _flex.Rows.Fixed To _flex.Rows.Count - 1
If Val(_flex(index, "Sales")) > 80000 Then
_flex.Rows(index).Selected = True
End If
Next
Console.WriteLine("There are now {0} rows selected",
_flex.Rows.Selected.Count)
// 在"销售"列中选择多于 8000 名销售的所有行。
_flex.SelectionMode = SelectionModeEnum.ListBox; for (int index = _flex.Rows.Fixed ; index < _flex.Rows.Count; index++)
{
if (Microsoft.VisualBasic.Conversion.Val(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(_flex\[index, "Sales"\])) > 80000)
{
_flex.Rows[index].Selected = true;
}
}
Console.WriteLine("There are now {0} rows selected",
_flex.Rows.Selected.Count);
"单元格区域"对象可以使你将单元格的任意组合作为一个简单的单元来工作。例如,下面的代码创建了一个"单元格区域"的对象,清除了范围内的数据,并赋予了它一个自定义样式:
Dim rg As CellRange = _flex.GetCellRange(3, 3, 10, 10) rg.Data = Nothing rg.Style = _flex.Styles("MyRangeStyle")
CellRange rg = _flex.GetCellRange(3, 3, 10, 10); rg.Data = null; rg.Style = _flex.Styles["MyRangeStyle"];
"单元格区域"的对象具有可以恢复区域样式的 StyleNew 的属性, 如果存在一个,或创建了一个新的,将其分配给该区域并返回它。在你不需要对格式进行全面控制的情况下,此属性是很方便的。例如,如果你想要做的是给这个区域设定一个红色的背景,你可以编写如下代码来实现:
Dim rg As CellRange = _flex.GetCellRange(3, 3, 10, 10) rg.StyleNew.BackColor = Color.Red
CellRange rg = _flex.GetCellRange(3, 3, 10, 10); rg.StyleNew.BackColor = Color.Red;
每个表格内的单元格除了在单元格中存储数据以外还都可以显示图像。这可以通过两种方式来实现:你可以通过使用"设置单元格图像"的方法,来将一个"图像"对象分配到一个单元格。这种方法可以允许你指定任意图像到每个单元格,并且当图像与单元格中的数据没有什么关系时这是很有用的。例如,你可能想使用图片作为一项指标来表明单元格中的数据是无效的。
你可以将一个"图像映射"指定到一列,表格就会将单元格中的数据自动映射到一个相应的图像。当图像包含了代表性的数据的情况下,这种方法是很有用的。例如,图像可能含有表示产品类型的图标。
C1FlexGrid 控件的主要优势之一就是,具有自定义整个表格和每个个体的单元格外观的几乎任一方面的能力。
为了控制单元格的内容如何被格式化,请将"格式化"属性设置到一个类似于你在.NET framework 中通过 String.Format 方法使用的格式字符串。例如,下面的代码显示了第一列的短日期和第二列的货币值:
' 短日期。
_flex.Cols(1).Format = "d"
' 货币值。
_flex.Cols(2).Format = "c"
_flex.Cols\[1\].Format = "c";
单元格内容的格式也是可以通过使用格式字符串对话框在设计时就进行设置的。格式字符串对话框的访问路径有两种,一种是可通过列任务菜单。另一种是可通过 C1FlexGrid 列编辑器。在"列任务"菜单上,单击"格式字符串"中的省略号按钮。
在 C1FlexGrid 列编辑器中,在左窗格中找到"格式"属性,并单击它旁边的省略号按钮。
注意:格式字符串对话框是特定列,而且只会更改所选定的列的"格式" 属性。
你还是可以使用自定义格式,就像你在 Visual Basic "格式"功能中所使用
的一样(例如,"#,###",等等)。
检索单元格数据你可以使用索引或"获取数据"方法来检索原始的表格数据。要检索格式
过的数据,请改为使用 GetDataDisplay 的方法。例如:
' 短日期。
_flex.Cols(1).Format = "d"
' 货币值。
_flex.Cols(2).Format = "c"
_flex(1, 2) = 10000
Console.WriteLine("Raw value: {0}", _flex(1, 2))
Console.WriteLine("Display value: {0}", _flex.GetDataDisplay(1, 2)) ' 行值:10000
// 短日期。
_flex.Cols[1\].Format = "d";
// 货币值。
_flex.Cols[2].Format = "c";
_flex[1, 2] = 10000;
Console.WriteLine("Raw value: {0}", _flex[1, 2]);
Console.WriteLine("Display value: {0}", _flex.GetDataDisplay(1, 2));
// 行值:10000
单元格的外观(对齐方式、字体、颜色、边框,等)是由"单元格样式" 对象处理的。表格有一个"样式"属性,它包含了用于设置单元格格式的所有样式的集合。这个集合有一些可以定义表格元素的外观的内置成员,如固定的和滚动的单元格,单元格选择,单元格定焦,等等。你可以更改这些样式来修改表格的外观,你也可以创建自己的自定义样式,并将它们分配给单元格,行或列。
改变内置的样式是改变表格外观的最简单的方式。例如,下面的代码可以
将所选定的部分的背景显示为红色,字体为绿色粗体:
Dim cs As CellStyle = _flex.Styles.Highlight cs.Font = New Font(_flex.Font, FontStyle.Bold) cs.ForeColor = Color.Green cs.BackColor = Color.Red
CellStyle cs = _flex.Styles.Highlight; cs.Font = new Font(_flex.Font, FontStyle.Bold); cs.ForeColor = Color.Green; cs.BackColor = Color.Red;
你还可以创建你自己的样式,并将它们分配到单元格,行和列。例如,下
面的代码可以创建一个自定义单元格样式并敬爱那个它分配给每一个第五行:
Dim cs As CellStyle = _flex.Styles.Add("Fifth") cs.BackColor = Color.Gray
Dim idex%
For idex = _flex.Rows.Fixed To _flex.Rows.Count - 1 Step 5
_flex.Rows(idex).Style = cs Next
CellStyle cs = _flex.Styles.Add("Fifth"); cs.BackColor = Color.Gray; for (int index = _flex.Rows.Fixed ; index <= _flex.Rows.Count - 1; index += 5)
{
_flex.Rows\[index\].Style = cs; |
下面是一个例子,显示了如何创建自定义样式,并将它们分配到行,列和单元格区域:
' 创建一个新的自定义样式。
Dim s As CellStyle = _flex.Styles.Add("MyStyle") s.BackColor = Color.Red
s.ForeColor = Color.White
' 将新的样式分配到一列。
_flex.Cols(3).Style = _flex.Styles("MyStyle")
' 将新的样式分配到一行。
_flex.Rows(3).Style = _flex.Styles("MyStyle")
' 将新的样式分配到一个单元格区域。
Dim rg As CellRange = _flex.GetCellRange(4, 4, 6, 6) rg.Style = _flex.Styles("MyStyle")
C#
// 创建一个新的自定义样式。
CellStyle s = _flex.Styles.Add("MyStyle"); s.BackColor = Color.Red;
s.ForeColor = Color.White;
// 将新的样式分配到一列。
_flex.Cols\[3\].Style = _flex.Styles\["MyStyle"\]; |
// 将新的样式分配到一行。
_flex.Rows\[3\].Style = _flex.Styles\["MyStyle"\]; |
// 将新的样式分配到一个单元格区域。
CellRange rg = _flex.GetCellRange(4,4,6,6); rg.Style = _flex.Styles\["MyStyle"\]; |
式,而不是靠编写代码来执行这一步操作。有关如何使用 C1FlexGrid 样式编辑器来自定义单元格的外观的更多详细信息,请参阅"C1FlexGrid 样式编辑器" (第 27 页)。
要根据单元格的内容设置其格式,你可以基于其内容使用"单元格变更"
事件来为单元格选择一种样式。例如,下面的代码可以根据单元格的内容为
"大货币值"创建一个新的样式,并将其应用于单元格:
Visual Basic
Dim cs As C1.Win.C1FlexGrid.CellStyle |
C#
CellStyle cs; private void Form1_Load(object sender, EventArgs e)
|
即使 "单元格样式"对象已经通过单元格外观(背景色和前景色、对齐方式、字体、边距、边框,等等)提供了很多控件,有时这仍是不够的。你可能想使用渐变背景,或直接在单元格中画一些自定义的图形。在这些情况下,你可以使用"绘制模式"属性和"自绘单元格"事件,通过每一个单元格是如何绘制的来实现全面控制。 "绘制模式"属性决定了 "自绘单元格"事件是否被激发。该事件可以是你兼顾到每一个单元格的视觉效果。"自绘单元格"事件中的参数,允许你对所显示的数据以及用于显示数据的样式,做出更改,甚至允许你完全接管并绘制单元格中你所想要的任何东西。 你可以通过在事件处理程序中设置 e.Text 和 e.Image 参数,来改变即将显示在单元格中的文本和图像。你也可以通过设置 e.Style 属性来改变将用于显示单元格的样式。请注意,你不应该修改样式参数的属性,因为这可能会影响到其他单元格。相反,你要分配一个新的"{*}单元格样式{*}"对象到"样式"参数。 例如,不要设置 *e.Style.ForeColor= Color.Red{*},而应该通过使用 *e.Style =* *_flex.Styles\["RedStyle"\]{*}将一个全新的样式分配给参数。 你还可以使用自己的绘图代码在单元格中进行绘制,甚至用命令将你的自定义代码与 *e.DrawCell* 方法合并到一起。例如,你可以使用 GDI 命令来绘制单元格的背景,然后调用 *e.DrawCell* 来显示单元格边框和内容。 可用的示例项目 有关高级的{*}自绘单元格{*}的一个范例,请参阅"ComponentOne 帮助中心" 的 *RtfGrid* 样品。 下面的代码显示了一个例子。它使用了渐变画笔来绘制所选定的单元格的背景。首先,代码会设置"绘制模式"属性,显示一个"{*}线性渐变画笔{*}"的对象并且在表格重新调整大小时更新画笔: \\ Visual Basic <span style="color: #1f497d">Dim m_GradientBrush As System.Drawing.Drawing2D.LinearGradientBrush</span> <span style="color: #1f497d">Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load</span> <span style="color: #1f497d">' 通过自绘单元格来使用画笔。</span> <span style="color: #1f497d">m_GradientBrush = New</span> <span style="color: #1f497d">System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle, Color.SteelBlue, Color.White, 45)</span> <span style="color: #1f497d">' 使用自绘来添加渐变。</span> <span style="color: #1f497d">_flex.DrawMode = C1.Win.C1FlexGrid.DrawModeEnum.OwnerDraw</span> <span style="color: #1f497d">End Sub</span> <span style="color: #1f497d">Private Sub _flex_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles _flex.Resize</span> <span style="color: #1f497d">' 当控件调整大小时更新渐变画笔。</span> <span style="color: #1f497d">m_GradientBrush = New</span> <span style="color: #1f497d">System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle,</span> <span style="color: #1f497d">Color.SteelBlue, Color.White, 45)</span> <span style="color: #1f497d">End Sub</span> C# <span style="color: #1f497d">System.Drawing.Drawing2D.LinearGradientBrush m_GradientBrush; private void Form1_Load(object sender, EventArgs e)</span> <span style="color: #1f497d">{</span> <span style="color: #1f497d">// 通过自绘单元格来使用画笔。</span> <span style="color: #1f497d">m_GradientBrush = new</span> <span style="color: #1f497d">System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle, Color.SteelBlue, Color.White, 45);</span> <span style="color: #1f497d">// 使用自绘来添加渐变。</span> <span style="color: #1f497d">_flex.DrawMode = DrawModeEnum.OwnerDraw;</span> <span style="color: #1f497d">}</span> <span style="color: #1f497d">private void _flex_Resize( object sender, System.EventArgs e)</span> <span style="color: #1f497d">{</span> <span style="color: #1f497d">// 当控件调整大小时更新渐变画笔。</span> <span style="color: #1f497d">m_GradientBrush = new</span> <span style="color: #1f497d">System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle,</span> <span style="color: #1f497d">Color.SteelBlue, Color.White, 45);</span> <span style="color: #1f497d">}</span> \\ |
景。在这个例子中,通过在事件参数中使用 "绘制单元格"方法,表格自己处理了自己的前景:
Visual Basic
Private Sub _flex_OwnerDrawCell(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.OwnerDrawCellEventArgs) Handles _flex.OwnerDrawCell
' 使用渐变画笔来绘制所选定的单元格的背景。
If _flex.Selection.Contains(e.Row, e.Col) Then
' 绘制背景。
e.Graphics.FillRectangle(m_GradientBrush, e.Bounds)
' 让表格绘制其内容。
e.DrawCell(C1.Win.C1FlexGrid.DrawCellFlags.Content)
' 我们已完成这个单元格的绘制。
e.Handled = True End If
C#
private void _flex_OwnerDrawCell( object sender, OwnerDrawCellEventArgs e) { |
基本的编辑模式允许用户在单元格中输入值。如果正在被编辑的列有一个特定的数据类型,由用户输入的值会自动转换成适当的数据类型。如果用户输入了不能转换成适当的数据类型的值,表格会激活"表格错误"事件并忽略该编辑。
对于许多应用来说,基本的编辑就足够了,但 C1FlexGrid 含有这样的属性和事件,它能让你控制编辑过程,并提供选择清单,编辑按钮和高级的验证控制。从版本 2.5 开始,C1FlexGrid 也有了外部编辑器的内置支持。这使你可以将任何一个控件作为表格编辑器使用(例如,现在你可以将 C1Input 控件作为表格编辑器使用。)
在以下主题中主要介绍了这些功能。
在许多应用中,单元格都有一个关于可能值的定义明确的列表。在这些情况下,你可以让用户从下拉列表中选择值。要做到这一点,必须建立一个字符串,其中包含所有的以管道字符分隔出来的选择(例如,"真|假|不知
道"),并将它分配到"组合列表"属性。每一列都可能有不同的列表。设置 "组合列表"属性,使表格在单元格旁边显示一个下拉框。用户可以单击此下拉框(或按 F2 键)来显示该单元格中可用选择的列表。
另一种常见的情况是即使单元格有共同价值的一个列表,但也应允许用户键入别的东西。这可以通过下拉组合,文本框和下拉列表的组合来实现。要创建一个组合,只需用管道字符(例如"|真|假不知道")来启动选择列表,然后将它像以前一样分配到"组合列表"属性。
例如,下面的代码会使表格在第一列上显示包含了颜色名称的下拉组合列表,并在第二列上显示一个下拉组合。当对第一列进行编辑时,用户必须从列表中选择一个值。当对第二列进行编辑时,用户也要选择一个值或输入什么别的东西:
' 下拉列表。
_flex.Cols(1).ComboList = "Red|Green|Blue|Red|White"
' 下拉组合。
_flex.Cols(2).ComboList = "|Red|Green|Blue|Red|White"
// 下拉列表。
_flex.Cols\[1\].ComboList = "Red|Green|Blue|Red|White"; |
// 下拉组合。
_flex.Cols\[2\].ComboList = "|Red|Green|Blue|Red|White"; |
你也可以在设计时使用"组合列表"对话框来设置"组合列表"属性。
"组合列表"对话框允许你选择你是想让列表显示为一个下拉列表,下拉组合,省略号按钮,还是文本框和省略号按钮。
你可以通过"列任务"菜单,或通过 C1FlexGrid 列编辑器来访问"组合列表"对话框。
注意:组合列表对话框是特定的列,并且只会更改所选定列的"组合列表"属性。
在某些情况下,在同一列中的单元格可能需要不同的列表。例如,一个属性列表可能会在第一列上显示显示所有的属性,并在第二列上显示他们的值。该值取决于属性本身,所以有效的选项一行接一行地改变。在这种情况下,你应该捕获"编辑前"事件,并且为当前单元格设置"组合列表"属性到一个适当的列表。"组合列表"属性适用于整个表格。
内置的"组合框"提供了一个默认的自动搜索功能。当用户输入一个值,选中的部分将移动到下一个适配的对象。您可以通过使用"编辑选项"属性来禁用此功能,也可以通过使用"自动搜索延迟"属性,在表格重新设置自动搜索缓冲之前来控制时间。
内置的"组合框"也有一个像 Visual Studio 的"属性"窗口中的编辑器那样的自动循环功能。当你双击一个具有与它相关联的列表的单元格,表格会自动选择下一个值。你也可以通过使用"编辑选项"属性来禁用此功能。
默认情况下,表格会将值以复选框的形式在布尔列显示(列的类型是由列对象的"数据类型"属性决定的)。如果你不想让让布尔值以复选框的形式显示出来,请将列的格式属性设置为一个字符串,此字符串包含会显示为"真" 和"假"的值。例如:
_flex.Cols("bools").Format = "Yes;No"
_flex.Cols\["bools"\].Format = "Yes;No"; |
在未绑定模式下,你可以通过使用 GetCellCheck 和 SetCellCheck 属性将复选框添加到任意单元格。复选框将会随着单元格中的任何文本来显示,而且你可以使用列的"图像对齐"属性来设置他们的位置。
复选框有两种类型:布尔和三态。布尔复选框可以在 CheckEnum.Checked 和 CheckEnum.Unchecked 状态之间进行切换。三态复选框可以在
CheckEnum.TSChecked, CheckEnum.TSUnchecked 和 CheckEnum.TSGrayed 之间进行循环切换。
如果某单元格有一个复选框并且"允许编辑"属性被设置为"真",用户可以通过用鼠标点击或按空格键或回车键来改变复选框的状态。
默认情况下,用鼠标或键盘切换复选框的值会将所有选中的复选框都切换掉。你可以通过使用"编辑选项"属性来禁用此功能。
如上所述的"组合列表"属性可以确保从列表中选择单元格的值。由用户选择的值被转换成适合于列的类型并存储在表格中,确切地说,是如果用户输入了值的话。
在许多情况下,单元格可以从定义明确的列表中采用一个值,但你想要显示的是一个包含实际值的〉用户界面友好的版本。例如,如果一个列包含产品编码,你可能想存储它的代码,但显示的产品名称来代替。
这可以通过"数据映射"属性来实现。此属性包含一个 IDictionary 对象的引用,它在什么是存储在表格中的什么是用户可见的之间建立了一个映射
(IDictionary 接口界面是在系统中定义的。集合的命名空间是由哈希表之类实现的)。
例如,下面的代码可以创建一个的包含颜色值和他们的名字的数据映射。
颜色存储于表格中,而向用户显示的是他们的名字:
Dim dtMap As Hashtable = New Hashtable() dtMap.Add(Color.Red, "Apple") dtMap.Add(Color.Green, "Forest") dtMap.Add(Color.Blue, "Sky") dtMap.Add(Color.Black, "Coal") dtMap.Add(Color.White, "Snow")
_flex.Cols(1).DataType = GetType(Color)
_flex.Cols(1).DataMap = dtMap
System.Collections.Hashtable dtMap = new System.Collections.Hashtable(); dtMap.Add(Color.Red, "Apple"); dtMap.Add(Color.Green, "Forest"); dtMap.Add(Color.Blue, "Sky"); dtMap.Add(Color.Black, "Coal"); dtMap.Add(Color.White, "Snow");
_flex.Cols\[1\].DataType = typeof(Color); |
_flex.Cols\[1\].DataMap = dtMap; |
配备了 Idictionary 接口的任何一类都可以作为一个"数据映射"来使用。例如,Hashtable,ListDictionary 和 SortedList 都提供了有效的数据映射。所不同的是,当他们在可编辑的列中使用时,下拉列表中条目的顺序将取决于类。
SortedList 类通过键值将各条目分类,Hashtable 通过任意顺序,而
ListDictionary 保持了那些条目被添加到列表中的顺序。正因为如此,
ListDictionary 通常是"数据映射"的最佳选择。
请注意,当单元格正在编辑中时,数据映射的键值必须是同一类型的。例如,如果一个列包含短整数(Int16),那么,与此列相关联的任何数据映射也应该是短整型的键值。如果将正整数(INT32)作为键值将不起作用。
下面的例子显示了它们的区别:
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As |
C#
private void Form1_Load(object sender, System.EventArgs e);
|
此外,如果列的"数据类型"属性被设置为一个枚举,表格将自动建立并使用一个含枚举中每个值的名称的数据映射。例如,下面的代码可以创建一个包含国家的枚举。国家的值存储在表格中,向用户显示的是他们的名字:
Private Enum Countries
NewYork
Chicago
NewOrleans
London
Paris
End Enum
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
_flex.Cols(1).DataType = GetType(Countries) End Sub
C#
private enum Countries
{
NewYork,
Chicago,
NewOrleans,
London,
Paris
}
private void Form1_Load(object sender, EventArgs e)
{
_flex.Cols\[1\].DataType = typeof(Countries); |
}
某些类型的单元格,除了文本框或下拉列表以外,可能还需要更复杂的编辑器。例如,如果一个列包含文件名称或颜色,它应该可以用一个对话框来编辑。
在这些情况下,你应该将 "组合列表"属性设置为省略号("...")。该控件将在单元格旁边显示一个按钮,当用户点击它时,将触发"单元格按钮点击"事件。你可以捕获该事件,显示对话框,并使用用户的选择来更新单元格的内容。
如果你在省略号前添加管道字符,那么用户也将被允许通过在单元格输入的方式来编辑单元格的内容。
默认情况下,单元格的按钮显示省略号。您可以使用"单元格按钮图像" 属性将图片指定到单元格按钮。
下面的示例演示了你应该如何使用单元格按钮来显示一个拾色器对话框,并在一列中选择一种颜色。
' 建立色列。
Dim c As C1.Win.C1FlexGrid.Column = _flex.Cols(1) c.DataType = GetType(Color)
' 显示单元格按钮。
c.ComboList = "..."
// 建立色列。
Column c = _flex.Cols\[1\]; |
c.DataType = typeof(Color);
// 显示单元格按钮。
c.ComboList = "...";
通过此代码设置该列,用户可以通过点击一个按钮来从一个对话框中选择一个颜色。下一步处理单元格按钮点击的代码:
Private Sub _flex_CellButtonClick(ByVal sender As Object, ByVal e As |
private void _flex_CellButtonClick( object sender, RowColEventArgs e)
{
// 创建"拾色器"对话框。
ColorDialog clrDlg = new ColorDialog();
// 初始化对话框。
if (_flex\[e.Row, e.Col\] == typeof(Color)) |
{
clrDlg.Color = (Color)_flex\[e.Row, e.Col\]; |
}
// 从对话框中获取新的颜色,并将它分配到单元格。
if (clrDlg.ShowDialog() == DialogResult.OK)
{
_flex\[e.Row, e.Col\] = clrDlg.Color; |
}
}
C1FlexGrid 控件还支持屏蔽编辑。当用户输入时,这种类型的编辑可以使用一种输入掩码来提供一个模板,并自动验证该输入。该掩码由"编辑掩码" 属性明确指定,它可以通过普通的文本字段和下拉组合区域来使用。
掩码字符串包括两种类型的字符:文字字符,这可以成为输入的一部分;模板字符,这是属于特定类别的占位字符(例如,数字或字母)。例如,下面的代码将一个编辑掩码"(999)999-9999"指定到第一列,该掩码包含的是电话号码,(数字"9"是一个可以代表任何数字的占位字符):
' 建立一个电话号码的编辑掩码。
_flex.Cols(1).EditMask = "(999) 999-9999"
// 建立一个电话号码的编辑掩码。
_flex.Cols\[1\].EditMask = "(999) 999-9999"; |
当你将"编辑掩码"属性设置为一个非空的字符串,会导致它必须使用内
置的屏蔽编辑,即便该列包含日期/时间值(通常,一个"日期时间提取器"控件可以用于编辑这些列)。如果你有只含时间(没有日期)的"日期时间" 列,这使用起来将格外方便。在这些情况下,你可以设置以下属性来使用一个屏蔽编辑器,而不是一个"日期时间提取器"控件:
flex.Cols(1).DataType = GetType(DateTime)
_flex.Cols(1).Format = "hh:mm tt"
_flex.Cols(1).EditMask = "99:99 LL"
flex.Cols\[1\].DataType = typeof(DateTime); |
_flex.Cols\[1\].Format = "hh:mm tt"; |
_flex.Cols\[1\].EditMask = "99:99 LL"; |
你也可以在设计时通过使用"输入掩码"对话框来设置"编辑掩码"属性。
要访问输入掩码对话框可通过以下两种途经,"列任务"菜单或
C1FlexGrid 列编辑器。
注意:输入掩码对话框是特定的列,并且只会更改所选定的列的编辑掩码属性。
有关建立掩码字符串的语法的详细信息,请参阅该控件参考资料部分的编辑掩码属性。
如果在同一列的不同单元格需要不同的掩码,需要捕获编辑前事件,并为当前单元格将编辑掩码属性设置一个的适当的值。
在许多情况下,为确保用户的数据输入是有效的,只有编辑掩码是不够的。例如,掩码不会让你指定一个可能值的范围,或以另一个单元格的内容为基础来验证当前单元格。
在这些情况下,需要捕获验证编辑事件,看看在"编辑器-文本"属性中包含的值是不是当前单元格的有效条目(在这一点上,单元格仍然有它的原始值)。如果该输入的是无效的,将"取消"参数设置为"真",表格将保持编辑模式直到用户输入一个有效的条目。
例如,将下面的代码验证输入到一个货币列,以确保输入的值处于 1000 和 10000 之间:
Visual Basic
Private Sub _flex_ValidateEdit(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.ValidateEditEventArgs) Handles _flex.ValidateEdit |
C#
private void _flex_ValidateEdit( object sender, ValidateEditEventArgs e)
|
"无"。
运行该项目并编辑第一列中的一些值。请注意表格如何定位和初始化
NumericUpDown 控件,以便你可以编辑单元格的值。当你完成对一个单元格的编辑,单击不同的单元格或按 TAB 键来移动到下一个。请注意新的值是如何应用到单元格的。
你也可以使用代码来给表格指定自定义编辑器:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' 创建自定义编辑器。
Dim editor as New NumericUpDown()
editor.BorderStyle = BorderStyle.None
' 将自定义编辑器分配到表格。
_flex.Cols(1).Editor = editor End Sub
private void Form1_Load(object sender, System.EventArgs e)
{
// 创建自定义编辑器。
NumericUpDown editor = new NumericUpDown();
editor.BorderStyle = BorderStyle.None;
// 将自定义编辑器分配到表格。
_flex.Cols\[1\].Editor = editor; |
}
创建自定义编辑器从 Control 基类派生出的任何控件都可以用来作为一个表格编辑器使用。这
是完全有可能的,因为在访问诸如"文本"和"界限"之类的属性,或诸如 "请假"和"文本变更"之类的事件时,表格对基类控件有足够的了解。在很多情况下,这种程度的支持就足够了。然而,在某些情况下,你可能想使用一些不那么密切地遵守基类的控件。例如,"日期时间提取器"控件有一个"值"属性,它应该用来检索编辑过的值,而不是文本的值。在这些情况下,你可以在 IC1EmbeddedEditor 接口上实现一个或多个方法来覆盖默认的行为。例如,在 C1Input 库中所有控件都支持
IC1EmbeddedEditor,因此,它与 C1FlexGrid(还有 C1TrueDBGrid)整合密切。
IC1EmbeddedEditor 接口相当简单,并且由于表格是使用后期绑定与之相结合的,你甚至不需要实现其所有成员。只需要落实那个对你的编辑器控件有意义的即可。
接口确实提供了足够的灵活性来使几乎所有的控件都能作为一个表格编辑
器使用。你甚至可以使用 UITypeEditor 这些类型来作为表格编辑器。要做到这一点,你需要一个包装类:
使用 UITypeEditor 包装类,你可以与 C1FlexGrid 一起使用任何
UITypeEditors。.NET 可以为编辑颜色,字体,文件名等提供几个 UITypeEditors。你也可以自己写 UITypeEditors,在某些情况下,这比写控件容易。
可用的示例项目
例如与 C1FlexGrid 一起使用内置的、自定义的和 UITypeEditor 编辑器,请在 ComponentOne 帮助中心上参阅"自定义编辑器"样本。
你可以通过阅读编辑属性值来确定表格是否处于编辑模式。如果这个属性恢复为"无效",则表格不是在编辑模式。不然,属性恢复一个引用值到 正在用于编辑该单元格的控件(该控件可能是一个"文本框",一个"组合框",或其他类型的控件),表格就是处于编辑模式。你可以"开始编辑"的方法将表格程式化地设定在编辑模式下,并使用"完成编辑"的方法来完成编辑。
你可以通过处理表格触发的编辑事件来进一步地控制整个编辑过程。在编辑一个单元格的过程中,表格会触发以下一系列事件:
事件 | 描述 |
编辑前 | 一个可编辑的单元格被选中时会触发该事件。你可以通过将事件的"取消"参数设置为"真"来防止单元格被编辑。你还可以修改"组合列表"的属性,以便使适当的下拉按钮被画在单元格 |
开始编辑 | 除了用户已经在单元格中敲下了一个键或点击了下拉按钮并真正开始编辑以外,该事件与"编辑前"事件类似。你仍然可以在这一点上取消编辑。请注意,在这一点上"编辑器"属性仍然是 |
安装编辑器 | 该事件触发的时间是编辑器控件已经创建并且配置好去编辑该单元格之后,但在它被显示之前。 |
| 在这一点上,你可以改变编辑器的属性(例如,在"文本框"编辑器中设置最大长度或密码字 |
验证编辑 | 该事件触发的时间是当用户完成编辑且编辑器的值被复制回表格之前。你可以通过从表格中检索它来检查原始值 (该事件可以提供单元格的坐标)。你可以通过 |
编辑后 | 该事件触发的时间是新的值已经被应用到单元格且编辑器已停用之后。你可以使用该事件来更新任何依赖于单元格值的东西(例如,分类汇总或排序)。 |
C1FlexGrid 控件允许你合并单元格,使他们跨越多个行或列。这个功能可以用来增强在表格上显示的数据的外观和清晰度。这些设置的作用与
HTML<ROWSPAN>和<COLSPAN>标签类似。
若要使单元格能够合并,以下两件事你必须要做:
如果相邻的单元格中含有相同的非空字符串,合并就会发生。没有一种方法能迫使一对单元格合并到一起。合并会在单元格内容的基础上自动完成。当相邻行中的值呈现重复数据的时候,这可以很容易地提供排序数据的合并后的视图。
单元格合并有几种可能的用途。例如,当文本溢出到相邻列时,你可以用它来创建合并的表头,合并后的数据视图,或表格。
要创建合并表头,你必须通过将表格的"允许合并"属性设置到 FixedOnly 来启动。然后,通过设置行和列的"允许合并"属性来指定要合并的行和列。
最后,将文本分配到标题单元格,以便你要合并的单元格具有相同的内容。
下面的代码显示了一个例子:
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As |
C#
private void Form1_Load(System.object sender, System.EventArgs e)
|
以下是结果:
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As |
private void Form1_Load( System.object sender, System.EventArgs e)
{
int i;
// 设置单元格合并。
_flex.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.RestrictCols; for (int i = _flex.Cols.Fixed; i <= _flex.Cols.Count - 1; i++)
{
_flex.Cols.AllowMerging = true;
}
以下是结果:
请注意合并单元格是如何在分组数据和使表格中的信息更容易理解上具有视觉效果的。
可用的示例项目
有关合并后数据视图用 C1FlexGrid 显示的一个示例,请参阅
ComponentOne 帮助中心中的"单元格合并"样本。
"允许合并"属性有两个设置,它们不同于其他的操作,也不需要你在特定的行和列来设置"允许合并"属性。
溢出设置
溢出设置会导致太长而不适合于一个单元格的文本蔓延到相邻的空单元格中。这种结果式的行为与 Microsoft Excel 中的类似。如果你在一个单元格中键入一个长项而相邻的单元格是空的,则该项可能会溢出所在单元格来占据所需要的尽可能多的空间。
例如,下面的图片显示了当"允许合并"属性设置为"溢出"且用户输入了不同长度的条目时,一个表格看起来是什么样子的:
节点设置
节点设置是与"溢出"类似,但只适用于勾勒节点。当数据被组合成组,且在节点行中所包含的格式中的信息与数据行不同时,此设置是非常有用的。
例如,下面的图片显示了,当数据被用 C1FlexGridBase.Subtotal 方法分组和总结,随后节点被设置为"允许合并"时,一个表格看起来是什么样子的:
此图片与在"创建汇总"(第 67 页)主题中的那个类似。所不同的是,现在小计行(节点)溢出到相邻的空单元格,改善了表格的外观。
你可以通过两种途径自定义默认的合并行为:
将一个自定义的 IComparer 类分配到 CustomComparer 属性。
到 CustomComparer 属性。
写一个从 C1FlexGrid 派生出的新类别,并通过提供自己的自定义合并逻辑来覆盖 GetMergedRange 虚拟方法。
可用的示例项目
"ComponentOne 帮助中心"的"自定义合并","自定义合并 2","自定义合并 3","自定义合并 4"。
C1FlexGrid 控件具有可以让你汇总数据并以分层方式显示的方法和属性。
若要汇总数据并添加聚合值,请使用 C1FlexGrid.Subtotal 方法。若要显示数据的分层视图,请使用"树型"属性。
C1FlexGrid.Subtotal 方法可以增加包含普通(非小计)行的汇总数据的分类汇总行。
分类汇总支持分层聚合。例如,如果你的表格包含销售数据,你可能会通过产品、地区和推销员来小计一下以得出总的销售数字。下面的代码说明了这一点:
Visual Basic
Private Sub ShowTotals()
' 在第零列显示大纲栏。
_flex.Tree.Column = 0
_flex.Tree.Style = TreeStyleFlags.Simple
' 清除现有的分类汇总。
_flex.Subtotal(AggregateEnum.Clear)
' 获得总计(使用-1,而不是列索引)。
_flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total")
' 每个产品的总计(第零列)。
_flex.Subtotal(AggregateEnum.Sum, 0, 0, 3, "Total {0}")
' 每个区域的总计(第一列)。
_flex.Subtotal(AggregateEnum.Sum, 1, 1, 3, "Total {0}")
' 基于内容来调整列宽。
_flex.AutoSizeCols() End Sub
C#
private void ShowTotals()
{
// 在第零列显示大纲栏。
_flex.Tree.Column = 0;
_flex.Tree.Style = TreeStyleFlags.Simple;
// 清除现有的分类汇总。
_flex.Subtotal(AggregateEnum.Clear);
// 获得总计(使用-1,而不是列索引)。
_flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total");
// 每个产品的总计(第零列)。
_flex.Subtotal(AggregateEnum.Sum, 0, 0, 3, "Total {0}");
// 每个区域的总计(第一列)。
_flex.Subtotal(AggregateEnum.Sum, 1, 1, 3, "Total {0}");
// 基于内容来调整列宽。
_flex.AutoSizeCols();
}
当 C1FlexGrid.Subtotal 方法添加了汇总信息行,它会自动分配汇总样式到新的行(有五个层级的分类汇总内置样式)。你可以使用"样式编辑器"或代码在设计器中改变大纲样式的属性,以此来自定义分类汇总行的外观。例如:
' 设置分类汇总的样式。
Dim cs As C1.Win.C1FlexGrid.CellStyle cs = _flex.Styles(C1.Win.C1FlexGrid.CellStyleEnum.GrandTotal) cs.BackColor = Color.Black cs.ForeColor = Color.White cs.Font = New Font(Font, FontStyle.Bold) cs = _flex.Styles(C1.Win.C1FlexGrid.CellStyleEnum.Subtotal0) cs.BackColor = Color.DarkRed cs.ForeColor = Color.White cs.Font = New Font(Font, FontStyle.Bold) cs = _flex.Styles(C1.Win.C1FlexGrid.CellStyleEnum.Subtotal1) cs.BackColor = Color.DarkBlue cs.ForeColor = Color.White
// 设置分类汇总的样式。
CellStyle cs; cs = _flex.Styles\[CellStyleEnum.GrandTotal\]; cs.BackColor = Color.Black; cs.ForeColor = Color.White; cs.Font = new Font(Font, FontStyle.Bold); cs = _flex.Styles\[CellStyleEnum.Subtotal0\]; cs.BackColor = Color.DarkRed; cs.ForeColor = Color.White; cs.Font = new Font(Font, FontStyle.Bold); cs = _flex.Styles\[CellStyleEnum.Subtotal1\]; cs.BackColor = Color.DarkBlue; cs.ForeColor = Color.White; |
执行此代码后,表格看起来是这样的:
总计行中包含的所有产品,地区和销售人员的销售总额。它是使用
groupOn 参数-1 在调用 C1FlexGrid.Subtotal 方法时被创建的。其他分类汇总显示产品和地区的销售总额。他们是用 Groupon 的参数值 0 和 1 创造的。
除了总量之外,你也可以计算其他分类汇总(例如,平均值或百分比),并计算每一行的几个汇总(例如,毛销售额及净销售额)。
由分类汇总的方法创建的小计行不同于其他普通行,主要体现在三个方面:
"树型样式"的属性来确定大纲树型图的位置和外观。
大纲树型图可以允许用户通过点击节点来折叠和展开表格的各部分。你可以使用大纲树型图来显示许多类型的信息,不仅仅是汇总这一种。下一主题将会指出如何创建一个自定义的大纲树型图来显示目录信息。
要想不使用分类汇总法来创建大纲树型图,你需要遵循以下步骤:
例如,下面的代码可以创建一个目录树:
Visual Basic
' 在窗体的顶部添加这些输入声明。
Imports System.IO
Imports C1.Win.C1FlexGrid
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' 初始化表格布局。
_flex.Cols.Fixed = 0
_flex.Cols.Count = 1
_flex.Rows.Count = 1
_flex.ExtendLastCol = True
_flex.Styles.Normal.TextAlign = TextAlignEnum.LeftCenter _flex.Styles.Normal.Border.Style = BorderStyleEnum.None
' 显示大纲树型图。
_flex.Tree.Column = 0
_flex.Tree.Style = TreeStyleFlags.SimpleLeaf
_flex.Tree.LineColor = Color.DarkBlue
' 填充表格。
AddDirectory("c:\", 0) End Sub
// 在窗体的顶部添加这些输入声明。 |
以上的代码初始化了表格布局,并且调用了"添加目录"程序,这意味着做了填充网格和建立的树型结构的工作:
Visual Basic
Private Sub AddDirectory(ByVal dir As String, ByVal level As Integer) |
"添加目录"是一个递归程序,它横跨当前目录及其所有子目录。在这个
private void AddDirectory(string dir, int level)
|
例子中,为了节省时间,树的大小局限在四个目录层次。在实际应用中,当它们被扩大时该程序应改为仅填充树型分支(请参阅式 FlexGrid for WinForms 教程(第 107 页))。
此代码可以创建一个表格,看起来如下图:
C1FlexGrid 控件独特的和流行的特点之一是能够添加层次分组到常规的非结构化数据。
为了实现这一目标,C1FlexGrid 介绍了节点行的概念。节点行不包含常规的数据。相反,他们作为表头在类似数据的分组下面运作,酷似一个常规
TreeView 控件中的节点。就像一个 TreeView 控件中的节点,节点行可以折叠和扩展,隐藏或显示它们所包含的数据。像一个 TreeView 控件中的节点的另一方面是,节点行有一个能定义节点层次的层级属性。较低级别的节点包含较高级别的节点。例如,假设你有一个可以显示客户名称,国家,城市,销售额的表格。这种典型的表格通常看起来是这样的 k
所有的信息都是存在的,但很难看到每一个国家或客户的总销售额。你可以使用 C1FlexGrid 的概述功能按国家(0 级)对数据进行分组,然后按每个国
家的城市(1 级),然后按每个城市的顾客(2 级)。下面是加入大纲之后的相同表格:
该表格会像前一个(被绑定到同一数据源的)一样显示相同的信息,但它增加了一个树型图,那里的每个节点都包含了它下面的数据摘要。节点可以折叠起来只显示摘要,或展开以显示细节。请注意,每个节点一行都可以显示多个列的摘要(在这种情况下,合计单位销售量并合计总金额)。
在这篇文章中,我们将引导你熟悉将一个普通的表格转变成一个更丰富的大纲型表格的过程。
加载数据
的。如果你的数据源在设计时是可用的,你可以使用 Visual Studio 属性窗口来设置表格的"数据源"属性,并且无需编写任何代码就可以将表格绑定到数据。
如果数据源在设计时是不可用的,你可以在代码中设置表格的"数据源" 属性。数据绑定代码看起来通常是这样的:
代码使用一个 OleDbDataAdapter 来用数据填充一个数据表,然后,将数据表分配给表格的"数据源"属性。
运行此代码后,你会看到在第一张图片中显示了一个"普通的表格"。要使这个普通的表格变成第二张图片中显示的那种大纲型表格,我们需要插入节点行来整理这个大纲。
创建节点行
节点行几乎都是同样的普通行,但以下情况除外:
public Form1()
{
InitializeComponent();
// 获取数据
var fields = @"
Country,
City,
SalesPerson,
Quantity, ExtendedPrice"; var sql = string.Format("SELECT {0} FROM Invoices ORDER BY {0}", fields);
var da = new OleDbDataAdapter(sql, GetConnectionString()); da.Fill(_dt); // 将表格绑定到数据
this._flex.DataSource = _dt;
// 为"总价"列设置格式
_flex.Cols\["ExtendedPrice"\].Format = "n2"; |
}
var row = _flex.Rows\[rowIndex\]; if (row.IsNode) |
{
// 该行是一个节点 var node = row.Node;
DoSomethingWithTheNode(node);
}
else
{
// 该行不是一个节点
}
3. 如果表格是未绑定的,那么你可以通过将 "是节点"属性设置为"真" 来将一些普通行变成节点行。请注意,这仅限于当表格处于未绑定的状态下。试图将一个普通的数据绑定行变成一个节点,可能会造成表格抛出一个异常。
以下的代码演示了你应该如何来执行一个"分组依据"程序,插入节点行并对一个给定列的近似值进行分组。
// 在给定列上将插入的同一个给定级别的节点分组
|
代码可以跳过现有的节点行(因此它可以被称为添加几个层次的节点)来扫描所有列,并记录分组列的当前值的轨迹。当当前值发生变化时,在第一滚动列会插入一个节点行,新组的名称会在此显示。
回到我们的例子,你可以使用此方法通过调用来创建两个级别的大纲:
void _btnGroupCountryCity_Click(object sender, EventArgs e)
{
GroupBy("Country", 0);
GroupBy("City", 1);
}
这很简单,但也有一些需要注意的事项。首先,该方法假定数据是按照大纲结构进行排序的。在这个例子中,如果数据是按照销售人员,而不是按照国别排序的,那么该大纲中每个国家都会对应好几个零级节点,这可能并不是你想要的。此外,"分组依据"程序可以插入许多行,这可能导致表格闪烁不定。为了避免这种情况,通常你应该先将"重绘"属性设置为"假",然后再作出更新,并且当完成后再将其设置回"真"。
为了解决这些问题,用来创建大纲的代码应该重新编写如下:
void _btnGroupCountryCity_Click(object sender, EventArgs e)
{
// 暂停重绘,同时更新
using (new DeferRefresh(_flex))
{
// 恢复原来的排序(按照国家、城市等)
ResetBinding();
// 按照国家、城市来分组
GroupBy("Country", 0);
GroupBy("City", 1);
}
}
"延迟刷新"类是一种简单的功能,它可以将表格的"重绘"属性设置为 "假",并且当它被破坏时可以恢复其原有的值。这将确保"重绘"属性 被完全地恢复,即便是在更新时发生例外的情况下。以下是 "延迟刷新"类的执行情况:
/// 实用工具类,用于封装在重绘版块的表格冗长的操作。 |
"绑定表格"的方法可以确保表格会按照我们的大纲结构所需的顺序排序。在我们的例子中,排序的顺序是按照国家、城市和销售人员。代码看起来则是像这个样子的:
如果你现在运行此代码,你会发现该节点行如预期一样创建,但大纲树型图是不可见的,所以你不能展开和折叠节点。下一节会对大纲树型图进行描述。
// unbind and re-bind grid in order to reset everything void ResetBinding()
|
大纲树型图与你在一个普通的"树型视图"控件中看到的非常相似。它显示了一个在每个节点行旁边有折叠或 扩展的图标的缩进结构,以便用户可以展开和折叠大纲以看到理想层级的细节。
大纲树型图可以在任何列中显示,这取决于由 Tree.Column 属性。在默认情况下,这个属性被设置为-1,这能导致大纲树型图根本不会被显示。在上面给出的例子中,为了显示大纲树型图,你可以使用这样的代码:
void _btnTreeCountryCity_Click(object sender, EventArgs e)
{
using (new DeferRefresh(_flex))
{
// 像以前一样按照国家和城市分组
_btnGroupCountryCity_Click(this, EventArgs.Empty);
// 显示大纲树型图
_flex.Tree.Column = 0;
// 自动调整尺寸以容纳树
_flex.AutoSizeCol(_flex.Tree.Column);
// 折叠细节节点
_flex.Tree.Show(1);
}
}
代码调用先前的方法来建立大纲,然后再将 Tree.Column 属性设置为零,以便在第一列显示大纲树型图。它还调用 C1FlexGrid.AutoSizeCol 的方法,以确保该列足够宽,能够容纳大纲树型图。最后,它调用 Tree.Show 的方法来显示所有零级节点(在这种情况下,就是城市那一层)并隐藏所有的细节。
// 显示大纲树型图
_flex.Tree.Column = 0;
_flex.Tree.Style = TreeStyleFlags.CompleteLeaf;
_flex.Tree.LineColor = Color.White;
_flex.Tree.Indent = 30;
大纲树型图会改变如下:
请注意标有"1","2"和"*"的、在左上角单元格上的按钮。点击这些按钮,会导致整个树型图折叠或展开到相应的级别。还请注意,更宽的缩进和线条将树型图既连接到普通行("Anne Dodsworth")又连接到节点行。
到目前为止,我们已经介绍了节点行和大纲树型图的创建。然而,为了使大纲真正有用,节点行应该包括它们所包含的数据的汇总信息。
如果你使用 C1FlexGrid.Subtotal 方法来创建一个大纲树型图,然后分类汇总将会被自动添加。这将在后面的章节中描述。
如果你像上面所描述的使用 Rows.InsertNode 方法来创建大纲树型图,那么你应该使用 C1FlexGrid。总结用来计算每个行的分组中的分类汇总方法,并且将结果直接插入节点行。
下面列举出来的 C1FlexGrid.Subtotal 方法演示了如何做到这一点:
// 在一个给定层级的每个节点添加分类汇总
|
"{*}添加分类汇总{*}"方法可以扫描所有表格中的行来寻找节点行。当一个理想层级的节点行被发现时, 该方法可以使用"获取单元格区域"的方法来检索节点的子行。然后它使用 C1FlexGrid.Aggregate 方法来计算整个范围内目标列中值的总和。{*}聚合{*}的调用包括一个可以避免重复计算的现有节点的"{*}排除节点{*}" 的标志。一旦小计已经被计算,它就会与通常的_{*}flex\[行,彩色\]{*}索引一起被分配到节点行的单元格。 请注意,这并不会以任何方式影响到数据源,因为节点行并没有绑定到数据。还要注意,该方法可以被用来将多个汇总添加到每个节点行。在这个例子中,我们将增加数量和总价列的汇总。除了总金额,你还可以添加其他的集合值,比如平均值,最高值,最低值等等。 现在我们可以用这种方法来创建一个包括节点行、大纲树型图以及分类汇 总的完整的大纲: <span style="color: #1f497d">void _btnTreeCountryCity_Click(object sender, EventArgs e)</span> <span style="color: #1f497d">{</span> <span style="color: #1f497d">using (new DeferRefresh(_flex))</span> <span style="color: #1f497d">{</span> <span style="color: #1f497d">// 恢复原来的排序(按照国家、城市、销售人员)</span> <span style="color: #1f497d">ResetBinding();</span> <span style="color: #1f497d">// 按照国家、城市分组</span> <span style="color: #1f497d">GroupBy("Country", 0); // 按 country (level 0) 分组</span> <span style="color: #1f497d">GroupBy("City", 1); // 按 city (level 1) 分组</span> <span style="color: #1f497d">// 添加每个国家、城市的总数</span> <span style="color: #1f497d">AddSubtotals(0, "ExtendedPrice"); //extended price per country (level 0)</span> <span style="color: #1f497d">AddSubtotals(0, "Quantity"); // quantity per country</span> <span style="color: #1f497d">(level 0)</span> <span style="color: #1f497d">AddSubtotals(1, "ExtendedPrice"); // extended price per city</span> <span style="color: #1f497d">(level 1)</span> <span style="color: #1f497d">AddSubtotals(1, "Quantity"); // quantity per city (level 1)</span> <span style="color: #1f497d">// 显示大纲树型图</span> <span style="color: #1f497d">_flex.Tree.Column = 0;</span> <span style="color: #1f497d">_flex.AutoSizeCol(_flex.Tree.Column);</span> <span style="color: #1f497d">_flex.Tree.Show(1);</span> <span style="color: #1f497d">}</span> <span style="color: #1f497d">}</span> 如果你现在运行该项目,你会看到一个由节点行组成的树型图,其中显示 了每个国家和城市的销售总数量和金额。虽然这非常好,但还是有一个小问题。如果你展开任何节点行,你会看到大量的重复值。一个给定的城市节点下的所有行都有相同的国家和城市: !worddav93d6bd43a4f75b9b63be7814494af425.png|height=305,width=529! 这是正确的,但它同时也是一种 屏幕实际使用面积的浪费。消除这些重复的值是很容易的;所有你所需要做的只是将正在被分组的列的{*}宽度{*}设置为零。 然而,当你这样做时,你应该记得将表格的"允许合并"属性设置为"节 点",以便使分配给节点行的文本可以溢出到可见列。(另一种选择是将节点的文本指定到第一个可见列,但合并通常是一个更好的解决方案,因为它可以让你在节点行使用更长的文本)。 下面是修改后的代码和最终结果: |
void _btnTreeCountryCity_Click(object sender, EventArgs e)
|
国家和城市列现在是不可见的,但它们的值仍然出现在节点行。折叠起来的的树型图可以显示每个国家和城市的总数。
在前面我们曾经提到,你也可以使用 C1FlexGrid 的 C1FlexGrid.分类汇总方法来创建树型图。除了可以在一个单一的步骤里同时做两件事以外,这种分类汇总的方法也可以像以上所描述的"分组依据"和"添加分类汇总"一样来执行相同的任务,因此它比其他的更高效一些。
下面的代码显示了你应该如何使用分类汇总的方法来完成我们之前做过的
同样的事情,只是要比之前更快一点而且不需要使用任何辅助方法:
void _btnTreeCountryCity_Click(object sender, EventArgs e)
{
using (new DeferRefresh(_flex))
{
// 恢复原来的排序(按照国家、城市、销售人员)
ResetBinding();
// group and total by country and city
_flex.Subtotal(AggregateEnum.Sum, 0, "Country",
"ExtendedPrice");
_flex.Subtotal(AggregateEnum.Sum, 0, "Country", "Quantity");
_flex.Subtotal(AggregateEnum.Sum, 1, "City", "ExtendedPrice");
_flex.Subtotal(AggregateEnum.Sum, 1, "City", "Quantity");
// 隐藏我们分过组的那些列
// (他们只有在树型图节点上已经出现过的那些重复的值)
// (但不要使它们不可见,这可能会隐藏节点的文本)
_flex.Cols\["Country"\].Width = 0; |
_flex.Cols\["City"\].Width = 0; |
_flex.AllowMerging = AllowMergingEnum.Nodes;
// 显示大纲树型图
_flex.Tree.Column = 0;
_flex.AutoSizeCol(_flex.Tree.Column);
_flex.Tree.Show(1);
}
}
分类汇总的方法非常方便和灵活。它包含多个重载,能够使你明确应该对
哪些列进行分组并按照索引或名称来合计总数,是否包括它插入节点行的标题,以及如何进行分组等等。下面的摘要介绍了可用的重载:
该方法的这个版本只有一个聚合类型作为一个参数。只有消除现有的分类汇总,然后再插入新的,它才是有用的。在这种情况下, aggType 参数要设置到 AggregateEnum.Clear。
Subtotal(AggregateEnum aggType, string groupBy, string totalOn)
这都是最常用的重载。参数都是聚合类型的,可以用来插入和分组和计算总数的列。列是可以通过索引或名称来引用的。而后者则是我们在上面的例子中使用过的。
Subtotal(AggregateEnum aggType, string groupBy, string totalOn, string caption) 这些重载添加了一个额外的标题参数。标题参数明确了被添加到新的节点行的文本,以确定要进行分组的值。默认情况下,要分组的值会显示出来,所以如果你是按国家分组的,节点行会显示"阿根廷","巴西",等等。如果你设置的标题参数为字符串,如"国家:{0}",那么该节点的行会相应地显示
"国家:阿根廷"来代替。
Subtotal(AggregateEnum aggType, string groupFrom, string groupTo, string totalOn, string caption)
这些重载将 groupby 函数参数分成了两个:groupFrom 和 groupTo。在默认情况下,无论什么时候 GroupBy 的值或以往的任何列发生了变化,分类汇总的方法都可以插入一个节点行。例如,即使 GroupBy 列的值是相同的,如果某一行在"城市"这一列有与前行中相同的值,但在 "国家"一栏有不同的值,那么分类汇总的方法也会认为行应该在不同的分组里面并且插入一个新的节点
行。这些聚合使你撤销该行为,并且指定在确定一组时应该考虑的列的范围。
到目前为止,我们已经讨论了如何使用高级别的 C1FlexGrid. Subtotal 方法以及较低级别的 Rows.InsertNode 和 Aggregate 方法来创建总计包含树型图和总计的大纲。
在这一点上,重要的是要记住,大纲树型图是基于数据而创建的,但是它不被任何方式约束,并且当表格或数据有变化时它不能自动维持现状。例如,如果用户在"总价"这一列修改了一个值,则分类汇总不会进行自动更新。如果用户将表格进行排序,那么数据将会被刷新,且分类汇总会消失。
有两种常见的方式可以用来维持大纲:
防止用户做任何将会使大纲无效的更改。这是最简单的选择。你可以设置表格的"允许编辑"、"允许拖动"和"允许排序"属性为"假",并且阻止任何会影响到大纲的更改。
当数据或表格有变化时更新大纲时。你会附加表格的"数据刷新后"、"排序后" 和"编辑后"事件的处理程序,并重新生成合适的大纲。
选项二通常是更有趣的,因为它提供了一个快捷而且简单的动态数据分析工具。这种方法是 C1FlexGrid 提供的"分析"示例来说明的。该示例创建了一个初始大纲,并允许用户对列进行重新排序。当列的顺序发生变化时,该示例自动对数据进行重新排序,并重新创建大纲。用户可以方便地创建简单的报告,来按国家、按产品、按销售人员等显示销售。
"节点"类提供了许多可以用来创建和管理大纲树型图的方法和属性。这些方法和属性中的许多都是基于标准的 TreeView 对象模型,因此他们应该熟悉大多数的开发者。
为了获得一个"节点"对象,你可以:
使用 Rows.InsertNode 方法的返回值:
Var node = _flex.Rows.InsertNode(index, level);
或者,你可以用行的节点属性来在现有的一行检索节点:
Var node = _flex.Rows\[index\].IsNode |
_flex.Rows\[index\].Node null; |
无论哪种方式,一旦你有了一个"节点"对象,你就可以使用以下属性和方法来操作它:
你还可以使用下列方法来探讨的大纲结构:
上面的讨论集中在绑定的情况下,即表格连接到提供数据的数据源的地方。你还可以创建绑定场景中的树型图和大纲。在这种情况下,事情其实比较简单,因为你可以通过将"是节点"属性设置为"真"来将任何一个节点变成一个节点行。
如果表格是未绑定的,它拥有所有显示的数据,并且当一个数据源拥有这些数据时,你做的是不可能的事情。例如,你可以像 C1FlexGrid 提供的"树型图节点"样品所显示的那样,使用 Move 方法来移动树型图周围的节点。
使用一个未绑定的表格中的节点与使用常规的"树型视图"控件的节点是非常相似的。
C1FlexGrid 控件具有让你保存、加载并打印表格的方法。
"保存表格"方法可以将表格内容保存到一个文本文件。该方法具有可以控制使用的分隔符类型的参数(例如,逗号、制表符、自定义分隔符),可以确定是否要保存固定的单元格还是只保存滚动的单元格,和要使用的编码类型(例如,ASCII 或 Unicode)。生成的文本文件随后可以被装入控件,或装入到其他支持逗号或制表符分隔的文件的应用程序(例如,Microsoft Excel)。
"加载表格"方法可以从文本文件中加载数据。你可以加载用"保存表格"方法或与其他应用程序创建的文本文件。文本文件的格式是相当简单的。单元格的内容可以保存为格式化字符串(完全是因为他们在屏幕上显示)。如果单元格的文本包含引号字符或单元格分隔符,那么单元格会被引号引起来。
Excel 文本文件中所使用的惯例。
文本文件不包含图片或格式信息。
"保存表格"方法有一个标志参数,它可以使你指定是否要保存整个表格或只保存其中的某些部分(滚动的、可见的、或选中的)。
从版本 2.5 开始,你可以使用"保存表格"和"加载表格"方法来保存和加载 Microsoft Excel 文件(.XLS)以及文本文件。这可以使你除了保存数据之外,还可以保存格式信息。要使用"保存表格"和"加载表格"方法来保存和加载 Excel 文件,只需简单地设置格式参数到 FileFormatEnum.Excel,并且像往常一样调用方法。你不需要在你的计算机上安装 Microsoft Excel。
Excel 文件中包含由"工作表"组成的"工作簿"。"保存表格"和"加载表格"方法总是用一个单一的工作表来保存工作簿,并从现有工作簿来载入第
一页工作表。如果你想额外的控制工作来加载或保存,请使用 SaveExcel,
LoadExcel,LoadExcelSheetNames 方法来代替。Excel 文件保存和加载的过程将转换大多数的数据类型和格式信息,包括行和列的尺寸、字体、颜色、格式、单元格对齐方式。然而,并不是所有的格式元素可以转换。例如,表格将加载 Excel 单元格的值,但它不会加载其隐含的公式。其他特征,如固定和合并单元格,图片,数据映射,单元格边框等,也没有被翻译。
你也可以从数据库中加载表格数据。这不同于数据绑定,它可以保持一个或多个控件和基础数据源之间的实时连接。为了从数据库加载数据,你可以使
用 DataReader 对象,如下所示:
Visual Basic
Private Sub _btnData_Click(ByVal sender As Object, ByVal e As |
C#
private void _btnData_Click(object sender, System.EventArgs e)
|
Visual Basic
' 获取表格的"打印文档"对象。 |
// 获取表格的"打印文档"对象。 |
表格中的数据过滤通常有两种形式:
下面介绍的代码样本,主要取自包括产品的两个新样本:列过滤器和自定义过滤器。请参阅表明行动的特点的完整的项目样本。
要使用以表头为基础的过滤器,C1FlexGrid 控件遵循了与用来实现列的移动和按大小排序的相同的模式。表格有一个新的"允许过滤"属性,可用于控制在控件级别过滤,并且表格的列对象也有一个"允许过滤"属性,可用于控制在列级别过滤。
要启用简单的过滤方案,用户只需设置表格的"允许过滤"属性为
"真"。然后,他们可以通过改变列的"允许过滤"属性的值来禁用或自定义过滤特定列的行为。列的"允许过滤"属性可以设置为下列值之一:
"条件过滤"结合了起来,两者都在下文中有所描述。
默认情况下,C1FlexGrid 控件会为使用指定的语言通过 CurrentUICulture 设置来将列过滤编辑器本地化。但是,你可以使用"语言"属性来推翻默认并指定当表格显示列过滤编辑器时应该使用的语言。
值过滤器 "值过滤器"概念上非常简单。它包含一个值的列表,并且只有该表中列出的值才会显示在表格上。如果列表设置为"无效的",那么该过滤为"没有活性的",且所有的值会被显示。这种类型的过滤器在过滤包含离散值,如名称或枚举,的列方面是被推荐的。
"值过滤"编辑器包括一个有复选框的值的列表。用户可以一次选中或取消选中所有值。采用先进的内置键盘导航来浏览长的列表是很容易的。编辑器中实现一个灵活的搜索缓冲区,可以使用户通过输入值的任何部分来找到值。例如,输入"希尔顿",将选择下一个其中包含"希尔顿"的值,包括"纽约希尔顿","王子爱德华希尔顿",或"巴黎希尔顿"。此外,敲 Ctrl+向上键或 Ctrl +向下键将会导航到下一个或前一个检查项目。使用目前分配给列的格式,值就会显示在列表上。
这个图像显示了"值过滤"编辑器。
条件过滤器
"条件过滤器"比其他的更加灵活。它不是选择特定的值,而是允许用户用运算符号来指定两个条件,如"大于" 、"开始"或"包含"。这种类型的过滤器在过滤包含"连续的"值的列,如数字,或日期/时间值,在这方面是被推荐的。 这个图像显示了"条件过滤"编辑器。
有过滤器适用于列来显示他们的标题过滤器的图标,甚至当鼠标不在他们上面的时候。在这个图像中你可以看到有"产品名称"和"数量"列标题的地方显示过滤器的图标。
内置的过滤器支持自动定位在以下语言:英语,西班牙语,法语,意大利语,葡萄牙语,德国,荷兰,俄罗斯,日本,希腊,丹麦,芬兰,挪威,瑞典文,阿拉伯文,波兰,中国,土耳其,波斯语,朝鲜语,希伯来语。该本地化资源是内置的,并不需要提供额外的 DLL 自定义过滤器
可以创建自定义过滤器来处理专门的值。例如,自定义过滤器在过滤颜色、地理或自定义数据类型方面值得推荐。
要创建一个自定义的过滤器,开发人员必须创建两个类:
自定义过滤器的样本包含三个自定义过滤器,用于过滤类型的颜色,日期/ 时间和字符串的值。
正如我们前面提到的这个文件,设置表格的"允许过滤"属性为"真",这足以让所有的列进行列过滤。然而,在许多情况下,你可能需要更精细的过滤控制。这可以通过修改个别列的"允许过滤"和"过滤"属性来实现。例如,下面的代码使能够启用过滤,但对过滤字符串类型的列进行了限制:
// 绑定和配置表格
flex.DataSource = dtProducts;
_flex.Cols\["UnitPrice"\].Format = "#,###.00"; |
// 启用过滤
_flex.AllowFiltering = true;
// 限制过滤 "字符串"类型的列
foreach (Column c in _flex.Cols)
{
c.AllowFiltering = c.DataType == typeof(string)
? AllowFiltering.Default
: AllowFiltering.None;
}
你可以通过创建过滤器并将他们分配到列,或通过检索现有的过滤器并修改其属性,来进一步自定义过滤过程。例如,下面的代码创建了一个"条件过滤器",配置它来选择所有以字母"C"开头的项目,然后分配这个新的过滤器给"产品名称"一列:
// 创建一个新的"条件过滤器"
|
当用户编辑他们或当他们适用于一列时,过滤器是适用的。当数据发生变化时,它们不会自动应用。
要将过滤器应用到从表格加载的当前的数据,请调用表格的"应用过滤器"方法。
例如,当用户编辑表格上的数据时,下面的代码启用了一个"应用过滤器"按钮。点击这个"应用过滤器"按钮即可应用该过滤器,并可以直到下一次的变化前禁用该按钮。
public Form1()
{
InitializeComponent();
// 获取一些数据
var da = new OleDbDataAdapter("select * from products", GetConnectionString()); var dtProducts = new DataTable(); da.Fill(dtProducts);
// 将表格绑定到数据_
flex.DataSource = dtProducts;
// 启用过滤
_flex.AllowFiltering = true;
// 监测变化以便启用"应用过滤器"按钮
_flex.AfterEdit += _flex_AfterEdit;
}
上面的代码可以将一个表格绑定到数据源,可以通过将"允许过滤"属性
设置为"真"来启用过滤器,并可以连接一个事件处理程序到"编辑后"事件。事件处理程序的执行情况如下:
void _flex_AfterEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e) |
此代码可以扫描所有列,以确定一个过滤器是否为任何列所定义。如果检测到有一个正在起作用的过滤器,该代码可以启用将过滤器应用于目前的数据的按钮。当单击该按钮时,下面的事件处理程序会执行如下:
private void _btnApplyFilters_Click(object sender, EventArgs e) |
该代码简单适用于所有活跃着的过滤器,并且直到下一次的变化前才禁用按钮。相反,如果你不需要一个按钮,而只是简单地想在每次编辑后应用该过滤器,你可以从"编辑后"事件处理器那里直接调用"应用过滤器",如下所示:
void _flex_AfterEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
{
_flex.ApplyFilters();
当过滤器被应用后,表格会通过将"可见"属性设置为"假"来隐藏一些行。但表格也能够激发可以允许你自定义过滤行为的"过滤前"和"过滤后" 事件。例如,假设,你不是要显示和隐藏行,而是要应用不同的风格来表明这些行是否能通过过滤器。这可以使用此代码来轻松地实现:
public Form1()
{
InitializeComponent();
// 配置表格_
flex.AllowFiltering = true; _flex.DataSource = dtInvoices;
// 为过滤器排除的行创建样式
var cs = _flexStyles.Styles.Add("filteredOut"); cs.BackColor = Color.LightSalmon;
cs.ForeColor = Color.DarkOrange;
// 连接过滤前和过滤后事件的处理程序
_flex.BeforeFilter += _flex_BeforeFilter;
_flex.AfterFilter += _flex_AfterFilter;
}
该代码可以创建一个将被用于显示未通过过滤器的行(而不是使他们不可见)的自定义样式。其次,该代码可以将处理程序与"过滤前"和"过滤后" 事件联系起来。事件处理程序列举如下:
在我们完成将自定义样式应用于被过滤掉的行之前,"过滤前"事件处理程序可以调用"开始更新"方法来防止表格自己进行重新绘制。"开始更新" 和"结束更新"方法可以代替已被弃用的"重绘"属性。
"过滤后"事件处理程序可以通过检索我们创建的样式来开始显示已筛选
// 在应用过滤器之前暂停绘制
|
出的行。然后它可以对表格中的行进行扫描,并且将新的样式应用于"可见" 属性设置为"假"的所有行。这些是被过滤器隐藏起来的行。一旦做到这一点,代码可以调用"结束更新"来恢复表格的更新。
我们相信,默认的过滤行为和 UI 可以解决牵涉到列过滤中的绝大多数情况。但是,你可以独立地使用这些列过滤器列类,来实现自己的自定义用户界面。
C1FlexGrid iTunes 风格的搜索框。
这种类型的搜索,可以允许用户键入一个值,并自动过滤表格的行来显示任何列中包含搜索字符串的行。为落实 iTunes 风格的搜索,我们以一个包含将作为一个过滤器参数的文本的文本框开始。我们还定义了一个定时器,它将在用户停止往文本框中输入的几毫秒后适用于过滤器:
public Form1() |
既然定时器已经被配置好了,所有我们需要做的就是在计时器滴答计时时来创建和应用过滤器:
// 在计时器滴答计时时应用过滤器
|
C1FlexGrid 控件拥有一套非常丰富的属性,方法和事件。但你却无需为了有效地使用该控件,而知道所有的这些。
下面的参考资料显示了其中最为重要的属性,方法,以及按使用类型来分组的事件。而且其中某些元素不只出现在一个分组中。想知道有关于此的更多详细信息,请选择下面的特定元素。表格布局
Rows, Cols, AutoSizeCols, ScrollBars
光标和选择
SelectionMode, Select, ShowCell, Row, Col, RowSel, ColSel, MouseRow, MouseCol, BeforeRowColChange, AfterRowColChange, BeforeSelChange, AfterSelChange, KeyActionTab, KeyActionEnter
编辑
AllowEditing, ComboList, EditMask, BeforeEdit, StartEdit, ValidateEdit, AfterEdit, StartEditing, FinishEditing, Editor, CellButtonClick, KeyDownEdit, KeyPressEdit, KeyUpEdit, ChangeEdit
获取和设置值
Item (indexer), GetData, GetDataDisplay, SetData, GetCellRange, GetCellImage, SetCellImage, Clip, FindRow, Aggregate, CellChanged
用户界面
AllowEditing, AllowMerging, AllowResizing, AllowDragging, AllowSorting, BeforeSort, AfterSort, AutoSearch, AutoSearchDelay, BeforeDragColumn, AfterDragColumn, BeforeDragRow, AfterDragRow, BeforeResizeColumn, AfterResizeColumn, BeforeResizeRow, AfterResizeRow, ShowScrollTip
概述和总结
Subtotal, Tree, IsNode, Level, Collapsed, BeforeCollapse, AfterCollapse
合并单元格
AllowMerging
数据绑定
DataSource, DataMember, AfterDataRefresh, AutoResize, GridError
保存、加载和打印表格
LoadGrid, SaveGrid, LoadExcel, SaveExcel, ClipSeparators, PrintGrid
OLE 拖放
DragMode, DropMode, BeforeMouseDown