下面章节的教程中,包含了一些例子用来说明 C1FlexGrid 控件中的一些主要特点。教程通过一步步创建几个简单的项目,详细描述了每个步骤。配套的光盘 CD 中包含了一些可作为参考的更复杂的例子。
这些教程是:
教程 | 描述 |
编辑教程 | 从一个基本的数据输入表格开始, 本教程演示如何实现数据格式化、复选框、下拉列表、输入掩码、数据验证、剪贴板支持。 |
大纲教程 | 演示如何使用 C1FlexGrid 的大纲功能来展示结构性(或分层)数据。 |
数据分析教程 | 从一个包含不同产品的、各地区的、销售人员的销售数据表格,来展示如何实现动态布局 |
编辑教程
本教程由一个基本的数据录入表格开始,然后增加了以下功能:
- 格式化
- 复选框
- 下拉列表
- 复杂的数据验证
- 剪贴板支持
- 自定义编辑器
最终的应用程序将类似于下面:
在 ComponentOne 主页的 Videos 中有一个本教程的视频。
步骤 1/6: 为这个编辑教程创建一个 C1FlexGrid 控件
启动一个新项目并点击工具箱中的 C1FlexGrid 图标向窗体中添加
C1FlexGrid 控件。
然后在窗体中点击或者拖动控件到一个合适的大小。
如果你没有在工具箱中找到 C1FlexGrid 控件,那么请在工具箱中右键单击然后选择"选择项…"。 然后在.Net 组件列表中查找 C1FlexGrid 控件并确保勾选上。 如果你在控件列表中无法找到控件,你也许需要重新安装控件包。
在属性窗口中为 C1FlexGrid 控件设置以下属性:
属性
设置
Dock
Fill
Cols.Count
5
Cols.Fixed
0
- 双击窗体的标题区域来打开代码窗口。在文件的顶端添加如下声明代码:
- Visual Basic
Imports C1.Win.C1FlexGrid
- C#
using C1.Win.C1FlexGrid;
这使得 C1FlexGrid 中定义的对象在整个项目都可见,并节省了很多需要敲的代码。
3. 可以通过列任务菜单、C1FlexGrid 列编辑器或者代码中来设计这些列。
在设计器中:
- 选中表格中的第一列。这将会打开这一列的列任务菜单。
- 在列标题和数据字段框中,输入 Product。
设置列标题和数据字段,其余列如下:
Column 1
Column Caption
Region
Data Field
Region
Column 2
Column Caption
Salesperson
Data Field
Salesperson
Column 3
Column Caption
Sales
Data Field
Sales
Column 4
Column Caption
Bonus
Data Field
Bonus
另外,还可以通过 C1FlexGrid 列编辑器来设置这些列:
- 通过在 C1FlexGrid 列任务菜单中点击设计器打开 C1FlexGrid 列编辑器。关于如何访问 C1FlexGrid 列编辑器的更多细节请查看访问 C1FlexGrid 列编辑器章节 (第 143 页)。
- 在右侧的窗格中选中 Column 0 。
- 在左侧窗格中,设置 Name 和 Caption 属性为 Product。
设置 Name 和 Caption 属性,其余列如下:
Column 1
Name
Region
Caption
Region
Column 2
Name
Salesperson
Caption
Salesperson
Column 3
Name
Sales
Caption
Sales
Column 4
Name
Bonus
Caption
Bonus
完成后点击 OK 来关闭编辑器。 在代码中:在 Form_Load 事件中添加如下代码:
- Visual Basic
' 创建列.
Dim cols As String = "Product|Region|Salesperson|Sales|Bonus"
Dim colNames As String() = cols.Split("|")
Dim i%
For i = 0 To C1FlexGrid1.Cols.Count - 1
C1FlexGrid1(0, i) = colNames
C1FlexGrid1.Cols.Name = colNames
Next
- C#
//创建列.
string cols = "Product|Region|Salesperson|Sales|Bonus"; string[] colNames = cols.Split(new char[] { '|' }); for (int i = 0; i <= this.c1FlexGrid1.Cols.Count - 1; i++)
{
c1FlexGrid1[0, i] = colNames[i]; c1FlexGrid1.Cols[i].Name = colNames[i];
}
运行程序并遵守以下规定:
就是这样!按下 F5 运行该项目,这样你就可以开始向控件中输入一些数据。按 F2 或者空格键来编辑现有条目,或者只是在现有的条目上键入新数据。
步骤 2/6: 设置列的类型和格式
当显示数字或者日期值时,您通常会希望采用一致的格式来显示这些值。 C1FlexGrid 控件允许你为每一列定制数据类型和格式。这些属性在设计器或者代码中都可以设置。
在设计器中
- 在表格中选中 Sales 列。这将会打开 Sales 列的列任务菜单。
- 设置 Data Type (数据类型)为 Decimal。
- 在 Format String(格式字符串)框中点击省略号按钮打开对话框。
- 在格式类型中选择 Currency(货币)。
- 点击 OK 关闭格式字符串对话框。
- 在表格中选中 Bonus 列。这将会打开 Bonus 列的列任务菜单。
- 设置数据类型为 Boolean。
另外,还可以通过 C1FlexGrid 的列编辑器来设置数据类型和格式属性:
- 通过 C1FlexGrid 任务菜单选择设计器来打开 C1FlexGrid 列编辑器 。 对于如何访问 C1FlexGrid 列编辑器的更多细节,请查看 访问 C1FlexGrid 列编辑器章节。
- 在右边的窗格中选择 Sales 列。
- 设置 DataType 属性为 Decimal。
- 点击 Format 属性旁边的省略号按钮。这将会打开 Format String (格式化字符串)对话框。
- 在格式化类型 中选择货币。
- 点击 OK 来关闭 Format String 对话框。
- 在右边的窗格中选择 Bonus 列。
- 设置 DataType 属性为 Boolean。
- 点击 OK 来关闭编辑器窗口。
代码中
要指定列的数据类型和格式,先添加步骤 1/6:为这个编辑教程创建一个C1FlexGrid 控件的代码后再添加下面的代码:
Visual Basic
'设置列的数据类型和格式。
Dim c As Column = C1FlexGrid1.Cols("Sales") c.DataType = GetType(Decimal)
' 货币类型.
c.Format = "c2" c = C1FlexGrid1.Cols("Bonus")
c.DataType = GetType(Boolean)
c.ImageAlign = ImageAlignEnum.CenterCenterC#
//设置列的数据类型和格式。
Column c = c1FlexGrid1.Cols["Sales"]; c.DataType = typeof(Decimal);
// 货币类型.
c.Format = "c2"; c = c1FlexGrid1.Cols["Bonus"]; c.DataType = typeof(bool);
c.ImageAlign = ImageAlignEnum.CenterCenter;运行程序,并遵守以下规定:
Sales 列新的代码格式,用来存储和显示货币值, Bonus 列用来处理布尔值。
如果你在 Sales 列输入一些数字和非数字值,你会发现表格将无法接受这些输入。
Bonus 列显示成复选框的样子,可以用鼠标、键盘来切换,这是布尔值列的默认行为。
注意格式化属性,它不以任何方式影响数据本身的值,只影响如何显示。步骤 3/6:纳入下拉列表
录入数据是一个乏味和容易出错的过程。下拉列表是个伟大的发明,因为它极大的减少了你必须做的输入操作,同时也就减少了出错的机会,这样就提高了数据的一致性。
让我们假设我们的教程项目只涉及三种产品的销售(Applets、Wahoos、和
Gadgets)。在四个区域(东、南、西、北), 并且这有三名全职销售人员
(玛丽、莎拉和宝拉)。
要在 C1FlexGrid 控件中将这个列表变为下拉列表, 所有你必须做的就是分别建立包含了每个项目的字符串(使用字符分割),并将它们分配到每个列对应的 ComboList 属性中去。
这个属性可以在代码或者设计器中设置。
在设计器中:
- 选中 Product 列。 这将会打开 Product 列事件菜单对话框。
- 在 Combo List 框中点击省略号按钮来打开 Combo List 窗口。
- 如下所示,输入 Applets、Wahoos、和 Gadgets。
- 点击 OK 来关闭 Combo List 对话框。
- 选中 Region 列。
- 在 Combo List 框中点击省略号 按钮。
- 输入 North、South、East、和 West 如下图所示:
- 点击 OK。
- 选中 Salesperson 列。
- 在 Combo List 框中点击省略号 按钮。
- 输入 Mary、Paula、和 Sarah 如下图所示:
12.选择 Dropdown Combo(下拉组合框)选项。
13.点击 OK。
另外,ComboList 属性同样可以在 C1FlexGrid 列编辑器中设置:
- 通过在 C1FlexGrid 任务菜单中选择设计器打开 C1FlexGrid 列编辑器。想要知道对于如何访问 C1FlexGrid 列编辑器的更多细节,请查看 访问 C1FlexGrid 列编辑器章节。
- 在右边的窗格中选择 Product 列 。
- 在左边的窗格中,设置 ComboList 属性为 Applets|Wahoos|Gadgets。
- 在右边的窗格中选择 Region column。
- 在左边的窗格中,设置 ComboList 属性为 North|South|East|West。
- 在右边的窗格中选择 Salesperson。
- 在左边的窗格中,设置 ComboList 属性为|Mary|Paula|Sarah。
- 点击 OK 来关闭编辑器.
在代码中:
要添加下拉列表项目,先添加步骤 2/6:设置列的类型和格式的代码后再添加下面的代码:
- Visual Basic
'设置下拉列表
C1FlexGrid1.Cols("Product").ComboList = "Applets|Wahoos|Gadgets"
C1FlexGrid1.Cols("Region").ComboList = "North|South|East|West" C1FlexGrid1.Cols("Salesperson").ComboList = "|Mary|Paula|Sarah"
- C#
'设置下拉列表
c1FlexGrid1.Cols["Product"].ComboList = "Applets|Wahoos|Gadgets"; c1FlexGrid1.Cols["Region"].ComboList = "North|South|East|West"; c1FlexGrid1.Cols["Salesperson"].ComboList = "|Mary|Paula|Sarah";
运行程序,并遵守以下规定:
请注意最后一个下拉列表是一个入力框 (文本入力光标)。这允许用户输入不在列表中的其他名字。换句话说,这些值将在下拉列表中可以编辑,而不是一个简单的下拉列表。
按 F5 再次运行该项目,然后移动光标。当您将光标移动到有下拉列表的列上时,下拉列表的按钮才为可见,你可以点击它来显示列表,或者只需要简单输入某个条目的第一个字母,使这个条目在下拉列表中变为高亮。
步骤 4/6: 添加数据验证
如果你为表格中的列指定了数据类型,表格就会确保只有这个类型的数据能够在这一列保存。这有助于防止错误发生,但是你会经常需要更加严格的验
证,以确保输入的数据是正确的。对于这一点,你应该使用 ValidateEdit 事件。
例如,想象一下,反托拉斯法规组织我们在北方地区销售我们的小程序。为了防止数据输入错误而带来昂贵的诉讼,我们希望防止用户在这个下拉列表中输入这个值。
以下事件用来检查在数据输入后编辑框中的数据是否合法, 添加下面的代码到窗体中:
Visual Basic
Private Sub C1FlexGrid1_ValidateEdit(ByVal sender As Object, ByVal e As
ValidateEditEventArgs) Handles C1FlexGrid1.ValidateEdit
Dim rgn As String = String.Empty Dim prd As String = String.Empty
' 收集我们需要的数据
Select Case e.Col prd = C1FlexGrid1.Editor.Text
rgn = C1FlexGrid1(e.Row, "Region") Case 1
prd = C1FlexGrid1(e.Row, "Product") rgn = C1FlexGrid1.Editor.Text End Select
' 我们可以在北部区域卖小程序
If prd = "Applets" And rgn = "North" Then
MsgBox("Warning: Regulation #12333AS/SDA-23 forbids " & _
"the sale of " & prd & " in region " & rgn & ". " & _ "Please verify input.") e.Cancel = True
End If
End Sub- C#
private void c1FlexGrid1_ValidateEdit( object sender, ValidateEditEventArgs e) prd = c1FlexGrid1.Editor.Text; rgn = (string)c1FlexGrid1[e.Row, "Region"]; break; case 1: prd = (string)c1FlexGrid1[e.Row, "Product"]; rgn = c1FlexGrid1.Editor.Text; break; |
运行程序,并遵守以下规定:
这个模块开始是收集需要验证的输入。请注意,被检查的值要恢复的话请使用 Editor.Text 属性。 这是必要的,因为这次编辑并没有应用到控件中去。如果检查失败了,这个模块将会显示一个警告然后将 Cancel 参数设置为 True,这样可以取消编辑并将单元格重新置为编辑模式,使用户可以再次尝试。
按 F5 再次运行该项目,然后再尝试输入一些错误的值。你会看到该控件将会拒绝它们。
步骤 5/6: 添加剪贴板的支持
Windows 剪贴板是一个在应用程序之间传输信息的非常有用的设备。
在 FlexGrid for WinForms 项目中添加剪贴板支持是相当容易的。只需要在代码或者设计器中简单的设置 AutoClipboard 属性为 True ,然后表格就会自动
的处理所有发送到剪贴板的标准键盘命令:如 CTRL+X 或者 SHIFT+DELETE 剪切,CTRL+C 或者 CTRL+INSERT 拷贝,CTRL+V 或者 SHIFT+INSERT 粘贴。
在设计器中:
在属性窗口中定位到 AutoClipboard 属性并将它设置为 True。
在代码中:
在添加完步骤 3/6:纳入下拉列表(第 112 页)之后,添加如下代码:
- Visual Basic
C1FlexGrid1.AutoClipboard = True
- C#
c1FlexGrid1.AutoClipboard = true;
另一个伟大的 Windows 功能,并与剪贴板密切相关,这就是 OLE 拖放操
作。C1FlexGrid 有两个属性, DragMode 和 DropMode。 这两个属性实现了这个功能。无论是在代码中还是在设计器中,只需要将这个两个属性设置为自动,你就能够将表格中选中的项目拖出程序并放置到其他应用程序中,如 Microsoft
Excel,或者从 Excel 中选择一个范围拖放到 C1FlexGrid 控件中。
在设计器中: 定位到 DragMode 和 DropMode 属性并将它们都设置为 Automatic。
在代码中:
在设置 AutoClipboard 属性后添加如下代码:
- Visual Basic
C1FlexGrid1.DragMode = DragModeEnum.Automatic
C1FlexGrid1.DropMode = DropModeEnum.Automatic
- C#
c1FlexGrid1.DragMode = DragModeEnum.Automatic; c1FlexGrid1.DropMode = DropModeEnum.Automatic;
运行程序,并遵守以下规定:按 F5 再次运行该项目,然后试着拷贝和粘贴一些数据。注意,你可以粘贴
一些非法的数据,因为我们的粘贴操作不触发任何的数据验证事件。 这是留给读者的练习。
步骤 6/6: 包含一个自定义编辑器
C1FlexGrid 拥有强大的内置输入编辑器:输入文字、文字掩码、列表选择、复选框等等。
但是在某些情况下,你可能想使用一个自定义编辑器来代替,也许是
C1Input 库中带的输入控件或者你自己写的输入控件。从版本 2.5 开始,FlexGrid 允许你轻松加愉快的插入自定义编辑器。要在教程工程的 Sales 列附加一个自定义编辑器,从往窗体上添加一个 NumericUpDown 控件开始。在属性窗口中,为 NumericUpDown 控件设置如下属性:
属性 | 设置 |
BorderStyle | None |
DecimalPlaces | 2 |
Maximum | 5000000 |
ThousandsSeparator | True |
Visible | False |
在 C1FlexGrid 任务菜单中选择设计器来打开表格的列编辑器。
选中 Sales 列(或代表 Sales 列的第 3 列),之后设置编辑器属性为
NumericUpDown。
运行程序,并遵守以下规定:
现在运行该项目,并尝试在 Sales 列中编辑一些值。请注意,表格现在使用
NumericUpDown 控件,而不是内置的编辑器。
这个控件已经进行了适当的位置调整、初始化和管理。当你将光标的焦点移动到不同的单元格中时,这个值将会保存到表格中。
但是这个自定义编辑器的行为与内置编辑器并不完全一样。例如:
- 当你开始编辑并键入一个数字,旧的值不会被清除。
- 编辑器的大小是不完全正确的(他看起来有点太小)。
- 当你使用回车键完成编辑时会有一声提示音出现。
你可以使用几个方法来克服这些问题。一种方法是使用编辑器的事件,但是这将使其难以在其他项目中重用这个控件。另一个方法是创建一个派生类并实现 IC1EmbeddedEditor 接口的一些方法,类似下面的这些代码:
Visual Basic
Public Class MyUpDown Inherits NumericUpDown
' 设置初始值
Public Sub C1EditorInitialize(ByVal value As Object, ByVal editorAttributes As IDictionary)
' 为初始值赋值
value = Convert.ChangeType(value, GetType(Decimal))
' 选择进入点
MyBase.Select(0, Int32.MaxValue)
End Sub
' 设置字体高度以便控件来控制整体高度
Public Sub C1EditorUpdateBounds(ByVal rc As Rectangle)
MyBase.FontHeight = rc.Height
Bounds = rc
End Sub
' 当用户按下回车键,禁止发出蜂鸣声
Protected Overrides Function ProcessDialogKey(ByVal keyData As Keys) As Boolean
If (keyData = Keys.Enter) Then
Parent.Focus()
If (Parent.Focused) Then SendKeys.Send("{Down}")
Return True
End If
Return MyBase.ProcessDialogKey(keyData)
End FunctionC#
internal class MyUpDown : NumericUpDown
{
//设置初始值
public void C1EditorInitialize(object value,
System.Collections.IDictionary editorAttributes)
{
//为初始值赋值
Value = (decimal)Convert.ChangeType(value, typeof(decimal));
//选择进入点
Select(0, int.MaxValue);
}
//设置字体高度以便控件来控制整体高度
public void C1EditorUpdateBounds(Rectangle rc)
{
base.FontHeight = rc.Height;
Bounds = rc;
}
//当用户按下回车键,禁止发出蜂鸣声
override protected bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter)
{
Parent.Focus(); if (Parent.Focused) SendKeys.Send("{Down}"); return true;
}
return base.ProcessDialogKey(keyData);
}
}
上面的代码实现了三个方法:
C1EditorInitialize 被调用来初始化编辑器。它设置了初始值然后选中整个条目。
这个将解决刚才提到的第一个问题。因为整个项目被选中,现在输入一个我们想要的字符将会取代目前的内容。
C1EditorUpdateBounds 被调用来定位正在编辑的单元格。NumericUpDown 控件的高度被设为以字体大小为基础自动增长(这就是为什么它相对单元格看起来太短)。代码设置了编辑器的 FontHeight 属性,所以它将被固定在单元格中。
ProcessDialogKey 方法被重写了,用来阻止当用户按下回车键发出的提示音。大纲教程
本教程演示如何使用 C1FlexGrid 作为一个大纲视图来显示结构(或层次)数据。
当作为一个大纲,C1FlexGrid 控件的行为就像一个树形控件,显示一些可以折叠、展开的节点,以展示包含下级数据的分支。
本教程可以让你加载一个 XML 文档到表格中,它将显示为一颗树。最终的应用程序看起来的效果如下:
步骤 1/5: 创建控件
新建一个项目并添加两个控件:- 在窗体的顶部附近添加一个命令按钮。
- 在按钮下面的区域添加一个 C1FlexGrid 控件。
如果你没有在工具箱中找到 C1FlexGrid 控件,那么请在工具箱中右键单击然后选择"选择项…"。 然后在.Net 组件列表中查找 C1FlexGrid 控件并确保勾选上。 如果你在控件列表中无法找到控件,你也许需要重新安装控件包。
在属性窗口中设置如下属性: 命令按钮
属性
设置
Dock
Top
Text
"Open XML File…"
C1FlexGrid
属性
设置
Dock
Fill
- 双击窗体的标题区域来打开代码窗口。在文件的最上方添加如下代码段:
- Visual Basic
Imports C1.Win.C1FlexGrid
- C#
using C1.Win.C1FlexGrid;
这使得 C1FlexGrid 中定义的对象在整个项目都可见,并节省了很多需要敲的代码。
3. 可以在设计器中使用属性窗口和编辑器来设置表格,或者在代码中输入
(或复制)以下代码: 在设计器中:
在属性窗口中为 C1FlexGrid 控件设置以下属性:
属性 | 设置 |
Cols.Count | 2 |
Cols.Fixed | 0 |
ExtendLastCol | True |
Rows.Count | 1 |
Tree.Column | 0 |
Tree.Style | SimpleLeaf |
为表格设置样式:
- 在 C1FlexGrid 任务菜单中选择样式打开 C1FlexGrid 样式编辑器。想要知道对于如何访问 C1FlexGrid 样式编辑器的更多细节,请查看 访问 C1FlexGrid 样式编辑器章节。
- 在内置样式中选择 Normal 。
- 设置 Border.Style 为 None,设置 TextAlign 属性为 LeftCenter,设置 WordWrap 属性为 False。
- 点击添加按钮。
- 将 CustomStyle1 重命名为 Data。
- 设置 BackColor 属性为 Control。
- 点击 OK 来关闭编辑器。
设置表格中的列:
- 在表格中选中 Column 0。这将打开第 0 列的列任务菜单。
- 将 Column Caption 设置为 Element。
- 取消勾选 Allow Editing 复选框。
- 选择 Column 1.
- 将 Column Caption 设置为 Text。
另外, 这些列也可以通过 C1FlexGrid 列编辑器来设置:
- 通过在 C1FlexGrid 任务菜单中选择设计器来打开 C1FlexGrid 列编辑器。想要知道对于如何访问C1FlexGrid列编辑器的细节,请查看访问C1FlexGrid 列编辑器章节。
- 在右侧窗格中选择 Column 0。
- 在左侧窗格中,将 AllowEditing 属性设置为 False ,设置 Caption 属性为Element。
- 在右侧窗格中选择 Column 1。
- 在左侧窗格中,将 Caption 属性设置为 Text。
- 点击 OK 来关闭编辑器。
在代码中:
- 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)
{
//初始化表格
c1FlexGrid1.Rows.Count = 1; c1FlexGrid1.Cols.Count = 2; c1FlexGrid1.Cols.Fixed = 0; c1FlexGrid1.ExtendLastCol = true; c1FlexGrid1[0, 0] = "Element";
c1FlexGrid1[0, 1] = "Text";
// 初始化大纲的树结构
c1FlexGrid1.Tree.Column = 0; c1FlexGrid1.Tree.Style = TreeStyleFlags.SimpleLeaf; c1FlexGrid1.Cols[0].AllowEditing = false;
//初始化样式
c1FlexGrid1.Styles.Normal.Border.Style = BorderStyleEnum.None; c1FlexGrid1.Styles.Normal.TextAlign = TextAlignEnum.LeftCenter; c1FlexGrid1.Styles.Normal.WordWrap = false; CellStyle cs = c1FlexGrid1.Styles.Add("Data"); cs.BackColor = SystemColors.Control;
}
运行程序,并遵守以下规定:
代码从一开始就设置表格的布局和标题的文本内容。
接下来,初始化大纲树属性并将第一列的 AllowEditing 属性设为 False 以防止 XML 节点能够被编辑。请注意,用户仍可以在包含每个 XML 节点数据的下一列进行数据的编辑。
现在空间已经设置好了。我们可以开始添加一些代码。步骤 2/5:读取数据并创建大纲
要读取数据,并建立大纲,向 Button1_Click 事件中添加一些代码和
GetXMLData 事物。
1. 双击命令按钮,将下面的代码添加到 Button1_Click 事件中去:Visual Basic
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
' 取得文件名称
Dim fo As OpenFileDialog = New OpenFileDialog() fo.DefaultExt = "xml"
fo.Filter = "XML Files (.xml)|.xml"
If fo.ShowDialog() <> Windows.Forms.DialogResult.OK Then Exit Sub
' 读取 XML 文件
Dim xdoc As System.Xml.XmlDocument = New System.Xml.XmlDocument() xdoc.Load(fo.FileName)
' 停止重绘,以提高速度。
C1FlexGrid1.Redraw = False
' 填充表格
C1FlexGrid1.Rows.Count = 1
GetXMLData(xdoc.ChildNodes(1), 0)
' 自动调整树的大小。
C1FlexGrid1.AutoSizeCol(0)
' 显示 0、1、2 层
C1FlexGrid1.Tree.Show(2)
' 开始重绘
C1FlexGrid1.Redraw = True
End Sub
C#
private void button1_Click(System.object sender, System.EventArgs e)
{
//取得文件名称
OpenFileDialog fo = new OpenFileDialog(); fo.DefaultExt = "xml"; fo.Filter = "XML Files (.xml)|.xml"; if ( fo.ShowDialog() != DialogResult.OK ) return;
//读取 XML 文件
System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument(); xdoc.Load(fo.FileName);
//停止重绘,以提高速度。
c1FlexGrid1.Redraw = false;
//填充表格
c1FlexGrid1.Rows.Count = 1;
GetXMLData(xdoc.ChildNodes[1], 0);
//自动调整树的大小。
c1FlexGrid1.AutoSizeCol(0);
//显示 0、1、2 层
c1FlexGrid1.Tree.Show(2);
//开始重绘
c1FlexGrid1.Redraw = true;
}
请遵守以下规定:
这个流程一开始是显示一个 OpenFileDialog 用来让用户选择一个 XML 文件加载到表格中。
当文件被选中,程序就开始加载文件到 XmlDocument 对象,并将文件中的内容解析到内存中去。
这个流程之后开始设置表格的重绘属性为 False 来控制表格暂停重绘。这种技显著的提高了程序的性能,你可以在向 C1FlexGrid 表格中添加大量数据的时候使用这个方法。
接下来,这个流程清除了为 1 的任何数据,并调用 GetXMLData 方法来填充数据到 XmlDocument。这个 GetXMLData 方法是这个指南中列出的条目中,最重要的一环。
在表格已被填充后,例程使用 AutoSizeCol 方法来根据第一列的内容来调整列的宽度,之后 Show 方法用来将需要显示的层级扩展到 0、 1、 和 2。 之后例程将 Redraw 属性设置回 True 以便 grid 开始重绘。
2. 这个 GetXMLData 例程是本教程中最有趣的一个。它贯穿整个
XMLDocument 对象,并建立大纲的树形结构。将下面的代码添加到窗体中去:Visual Basic
Private Sub GetXMLData(ByVal node As System.Xml.XmlNode, ByVal level As Integer)
' 跳过注释节点
If node.NodeType = System.Xml.XmlNodeType.Comment Then
Exit Sub
End If
' 为这一个节点添加一个新行
Dim row As Integer = C1FlexGrid1.Rows.Count
C1FlexGrid1.Rows.Add()
' 为这个新行添加数据
C1FlexGrid1(row, 0) = node.Name
If node.ChildNodes.Count = 1 Then
C1FlexGrid1(row, 1) = node.InnerText
C1FlexGrid1.SetCellStyle(row, 1, C1FlexGrid1.Styles("Data")) End If
' 如果这个节点有"Name" 子节点的话,将它保存起来作为一个 ToolTip 提示使用。
If node.ChildNodes.Count > 0 Then
Dim ndName As System.Xml.XmlNode = node.SelectSingleNode("Name")
If Not (ndName Is Nothing) Then
C1FlexGrid1.Rows(row).UserData = ndName.InnerText
End If
End If
' 如果此节点有子节点,将它们都取出来
If node.ChildNodes.Count > 1 Then
' 将当前行作为节点
C1FlexGrid1.Rows(row).IsNode = True C1FlexGrid1.Rows(row).Node.Level = level
' 使用递归来取得子节点
Dim child As System.Xml.XmlNode
For Each child In node.ChildNodes
GetXMLData(child, level + 1)
Next
End If
End SubC#
private void GetXMLData(System.Xml.XmlNode node, int level)
{
//跳过注释节点
if ( node.NodeType == System.Xml.XmlNodeType.Comment )
{
return;
}
//为这一个节点添加一个新行
int row = c1FlexGrid1.Rows.Count; c1FlexGrid1.Rows.Add();
//为这个新行添加数据
c1FlexGrid1[row, 0] = node.Name; if ( node.ChildNodes.Count == 1 )
{
c1FlexGrid1[row, 1] = node.InnerText; c1FlexGrid1.SetCellStyle(row, 1, c1FlexGrid1.Styles["Data"]);
}
//如果这个节点有"Name" 子节点的话,将它保存起来作为一个 ToolTip 提示使用。
if (node.ChildNodes.Count > 0)
{
System.Xml.XmlNode ndName = node.SelectSingleNode("Name"); if (ndName != null)
{
c1FlexGrid1.Rows[row].UserData = ndName.InnerText;
}
}
//如果此节点有子节点,将它们都取出来
if ( node.ChildNodes.Count > 1 )
{
//将当前行作为节点
c1FlexGrid1.Rows[row].IsNode = true;
c1FlexGrid1.Rows[row].Node.Level = level;
//使用递归来取得子节点
foreach (System.Xml.XmlNode child in node.ChildNodes) GetXMLData(child, level + 1);
}
}请遵守以下规定:
程序一开始跳过了 XML 注释节点,然后使用 Rows.Add 来向表格中添加一个新行。
接下来,程序开始设置节点的名称并检查该节点是否拥有孩子节点。在这种情况下,该节点被解释为一个数据节点,之后将该节点的 InnerText 属性复制到新行的第二列。代码还设置了当窗体被创建时,包含数据的单元格的样式为自定义的"Data"样式 。接下来的代码块检查看看是否这个节点包含一个名为
"name"的子节点。如果有,那么"name"节点的内容会被分配到新行的
UserData 属性中去。这个值将会被用于实施工具提示,这样即使节点名称被折叠起来了,用户也能够看到。
最后,如果该节点有孩子节点, GetXMLData 程序会调用自身来递归添加他们到表格中。
运行程序,并遵守以下规定: 该项目可以加载 XML 并显示它们,用户可以点击折叠或者展开节点。
接下来的步骤中会添加一些改进,使得应用程序更加容易使用。步骤 3/5:添加自定义的鼠标和键盘处理
C1FlexGrid 为你提供了展开和折叠的操作,但是你可以扩展并自己定制这些行为。每当一个分支被展开或折叠起来,控件会触发 BeforeCollapse 和 AfterCollapse 事件,所以你可以在这些事件中做一些回应。此外,您可以在代码中使用 Collapsed 属性来获取和设置每个分支的折叠状态。
在本教程中,我们将捕获当用户鼠标双击或按下回车键来展开或者折叠节点时的 DoubleClick 和 KeyPress 事件。添加下面的 DoubleClick 和 KeyPress 事件代码到窗体上:
Visual Basic
Private Sub C1FlexGrid1_DoubleClick(ByVal sender As Object, ByVal e As
EventArgs) Handles C1FlexGrid1.DoubleClick
If C1FlexGrid1.MouseCol = 0 Then
ToggleNodeState()
End If
End Sub
Private Sub C1FlexGrid1_KeyPress(ByVal sender As Object, ByVal e As
KeyPressEventArgs) Handles C1FlexGrid1.KeyPress
If e.KeyChar = vbCr Then
ToggleNodeState()
End If
End Sub
Private Sub ToggleNodeState()
' 如果当前行不是节点,则什么也不做
Dim r As Row = C1FlexGrid1.Rows(C1FlexGrid1.Row)
If Not r.IsNode Then Exit Sub
'切换折叠状态
r.Node.Collapsed = Not r.Node.Collapsed End Sub
C#private void c1FlexGrid1_DoubleClick( object sender, EventArgs e)
{
if ( c1FlexGrid1.MouseCol == 0 )
{
ToggleNodeState();
}
}
private void c1FlexGrid1_KeyPress( object sender, KeyPressEventArgs e)
{
if ( e.KeyChar == 13 )
{
ToggleNodeState();
}
}
private void ToggleNodeState()
{
//如果当前行不是节点,则什么也不做
Row r = c1FlexGrid1.Rows[c1FlexGrid1.Row]; if (! r.IsNode ) return;
//切换折叠状态
r.Node.Collapsed = !r.Node.Collapsed;
}运行程序,并遵守以下规定:
事件处理程序检查用户是否双击第一列或按下回车键,然后调用
ToggleNodeState 程序。ToggleNodeState 检查当前行是否是一个节点行,如果是,则切换 Collapsed 属性值。步骤 4/5:允许/阻止编辑
回想一下,我们设置第一列的 AllowEditing 属性为 False。这可以防止用户编辑第一列中的任何单元格。我们也想防止用户在节点行的第二列输入任何数
据。要做到这一点,添加下面的代码来处理 BeforeEdit 事件:- Visual Basic
Private Sub C1FlexGrid1_BeforeEdit(ByVal sender As Object, ByVal e As
RowColEventArgs) Handles C1FlexGrid1.BeforeEdit
' 如果当前行是一个节点,则不允许编辑
Dim r As Row = C1FlexGrid1.Rows(C1FlexGrid1.Row)
If r.IsNode Then e.Cancel = True End Sub
C#
private void c1FlexGrid1_BeforeEdit( object sender, RowColEventArgs e)
{
//如果当前行是一个节点,则不允许编辑
Row r = c1FlexGrid1.Rows[c1FlexGrid1.Row]; if (r.IsNode ) e.Cancel = true;
}步骤 5/5: 实现工具提示
在结束本教程前,我们将向大纲中添加工具提示。这个工具提示将把每一行中 UserData 属性中保存的上述 GetXMLData 的文本显示出来。 当用户将鼠标移到它的父节点时,工具提示将显示"Name" 节点的内容。这是非常有用的,因为当父节点折叠起来时,"Name"节点是不可见的。
- 添加一个 ToolTip 控件到窗体上。
- 添加下面的代码来处理表格上的 MouseMove 事件:
Visual Basic
Private Sub C1FlexGrid1_MouseMove(ByVal sender As Object, ByVal e As
MouseEventArgs) Handles C1FlexGrid1.MouseMove
' 为当前单元格检查 ToolTip
Dim tip As String
If C1FlexGrid1.MouseCol = 0 And C1FlexGrid1.MouseRow > 0 Then
tip = C1FlexGrid1.Rows(C1FlexGrid1.MouseRow).UserData
' 如果与当前提示不同,则设置 ToolTip。
If tip <> ToolTip1.GetToolTip(C1FlexGrid1) Then
ToolTip1.SetToolTip(C1FlexGrid1, tip)
End If
End If
End Sub
C#
private void c1FlexGrid1_MouseMove( object sender, MouseEventArgs e) tip = (string)c1FlexGrid1.Rows[c1FlexGrid1.MouseRow].UserData;
|
运行程序,并遵守以下规定:
代码首先使用 MouseRow 属性和 MouseCol 属性来检查当前鼠标下的单元格。如果鼠标是在包含 ToolTip 文本行的第一列,则检索该行文本。否则,
ToolTip 文本设置为 Nothing。
然后程序会比较当前和新的 ToolTip 文本,如有必要的话则通过调用
ToolTip 控件的 SetToolTip 方法来更新文本。
这样就结束了本教程。你可以在很多方面来扩展这个项目,包括将改动保存到 XML 文档中,添加、删除和移动节点,为不同类型的数据使用不同的样式等等。
数据分析教程
本教程结合了一些 C1FlexGrid 控件非常有用的功能来实现数据表的动态视图。这个应用程序是从一个简单的数据绑定表格开始,表格中包含了销售数据
(来自 NorthWind 数据库),之后添加了一下功能:
- 动态布局(列顺序)
- 自动排序
- 合并单元格
- 自动合计
- 大纲视图
最终的程序看起来如下图所示。用户可以拖动前三列来分组数据,包括
salesperson、 country、 和 product name。当一列被拖动,最终合计会自动的重新计算并重建大纲树。
步骤 1/4: 为数据分析教程创建 C1FlexGrid 控件
创建一个新的项目,并在工具箱中点击 C1FlexGrid 图标来在窗体中添加一
个 C1FlexGrid 控件,然后点击窗体并拖动控件直到控件有一个合适大小。
如果你没有在工具箱中找到 C1FlexGrid 控件,那么请在工具箱中右键单击然后选择"选择项…"。 然后在.Net 组件列表中查找 C1FlexGrid 控件并确保勾选上。 如果你在控件列表中无法找到控件,你也许需要重新安装控件包。
- 在 C1FlexGrid 事件菜单中,点击 Dock 来将控件适用到父容器中。将表格的 Dock 属性设置为 Fill 以便表格填充整个窗体。
- 双击窗体标题栏区域来打开代码窗口。在文件的最上端,添加下面的代码段:
- Visual Basic
Imports System.Data.OleDb
Imports System.ComponentModel Imports C1.Win.C1FlexGrid
- C#
Using System.Data.OleDb;
Using System.ComponentModel;
Using C1.Win.C1FlexGrid;
这使得 C1FlexGrid 中定义的对象和 OleDb 程序集在整个项目都可见,并节省了很多需要敲的代码。
步骤 2/4: 初始化和填充表格
要设置表格并用我们想要分析的销售数据来填充表格,可以在设计器中或在代码中设置布局属性和样式属性,并使用 GetDataSource 方法来填充表格。
- 在设计器中或在代码中设置布局属性和样式属性。
在设计器中: 在属性窗口中,设置如下属性:
属性 | 设置 |
AllowEditing | False |
AllowSorting | None |
AllowMerging | Nodes |
ExtendLastCol | True |
SelectionMode | Cell |
Tree.Style | Simple |
Tree.Column | 1 |
- 通过在 C1FlexGrid 任务菜单选择样式打开 C1FlexGrid 样式编辑器。想要知道对于如何访问 C1FlexGrid 样式编辑器的更多细节,请查看访问 C1FlexGrid 样式编辑器章节
- 从内置样式列表中选择 Normal。
- 设置 Border.Style 属性为 None,设置 Trimming 属性为 EllipsisCharacter。
- 从内置样式列表中选择 Subtotal0。
- 设置 BackColor 属性为 Gold,设置 ForeColor 属性为 Black。
为 Subtotal1 和 Subtotal2 设置如下属性:
Subtotal1
BackColor
Khaki
ForeColor
Black
Subtotal2
BackColor
LightGoldenrodYellow
ForeColor
Black
- 点击 OK 来关闭编辑器。
在代码中:
添加下面的代码到 Form_Load 事件中来设置表格的布局和样式:
- Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As EventArgs) Handles MyBase.Load |
C#
private void Form1_Load( System.object sender, EventArgs e) c1FlexGrid1.AllowEditing = false; c1FlexGrid1.AllowSorting = AllowSortingEnum.None; c1FlexGrid1.AllowMerging = AllowMergingEnum.Nodes; c1FlexGrid1.SelectionMode = SelectionModeEnum.Cell; c1FlexGrid1.ExtendLastCol = true; c1FlexGrid1.Cols[0].Width = c1FlexGrid1.Cols.DefaultSize / 4; c1FlexGrid1.Tree.Style = TreeStyleFlags.Simple; c1FlexGrid1.Tree.Column = 1;
c1FlexGrid1.Styles.Normal.Border.Style = BorderStyleEnum.None; c1FlexGrid1.Styles.Normal.Trimming = StringTrimming.EllipsisCharacter; CellStyle s = c1FlexGrid1.Styles[CellStyleEnum.GrandTotal]; s.BackColor = Color.Black; s.ForeColor = Color.White; s = c1FlexGrid1.Styles[CellStyleEnum.Subtotal0]; s.BackColor = Color.Gold; s.ForeColor = Color.Black; s = c1FlexGrid1.Styles[CellStyleEnum.Subtotal1]; s.BackColor = Color.Khaki; s.ForeColor = Color.Black; s = c1FlexGrid1.Styles[CellStyleEnum.Subtotal2]; s.BackColor = Color.LightGoldenrodYellow; |
常规的一开始设置表格的布局和一些样式。
- 通过添加下面的代码到 Form_Load 事件中来将 C1FlexGrid 绑定到数据源。
- Visual Basic
' 将 C1FlexGrid 绑定到数据源。
C1FlexGrid1.DataSource = GetDataSource()
- C#
//将 C1FlexGrid 绑定到数据源。
c1FlexGrid1.DataSource = GetDataSource();
下面例行列出通过结合 GetDataSource 方法来创建一个数据源。
- 将最后三列的 AllowDragging 属性设置为 False,用来锁定最后三列位
置。这么做的目的是为了防止用户在这些列中做数据分组(这些列中的值是由每一行的不同得来的)。这个属性可以在在设计器中或者在代码中设置:在设计器中:
- 在表格中选择 Column 4。这将会打开 Column 4 的列任务菜单。
- 取消勾选 Allow Dragging 复选框。
- 为 Column 5 和 Column 6 重复做上面两步。
另外, 这个 AllowDragging 属性同样可以在 C1FlexGrid 列编辑器中设置:
- 在 C1FlexGrid 任务菜单中选择设计器来打开 C1FlexGrid 列编辑器。想要知道对于如何访问 C1FlexGrid 列编辑器的更多细节,请查看访问 C1FlexGrid 列编辑器章节(第 143 页)。
- 在右侧窗格中选择 Column 4。
- 在左侧窗格中,设置 AllowDragging 属性为 False。
- 将 Column 5 和 Column 6 的 AllowDragging 属性设置为 False。
- 不要关闭编辑器。
在代码中:
将下面的代码添加到 Form_Load 事件中:
Visual Basic
' 防止用户拖动最后三列。
C1FlexGrid1.Cols(4).AllowDragging = False
C1FlexGrid1.Cols(5).AllowDragging = False
C1FlexGrid1.Cols(6).AllowDragging = False
- C#
//防止用户拖动最后三列。
c1FlexGrid1.Cols[4].AllowDragging = false; c1FlexGrid1.Cols[5].AllowDragging = false; c1FlexGrid1.Cols[6].AllowDragging = false;
- 将 Sales Amount 列的 Format 属性设置一下,以便总和可以显示为货币样式。
这个操作可以在设计器中或者在代码中做到:在设计器中:
- 在表格中选择 Column 6。
- 在 Format String 框中点击省略号按钮来打开 Format String 窗口。
- 在 Format type 中选择 Currency(货币)。
- 点击 OK 来关闭 Format String 窗口。
另外, Format 属性也可以通过使用 C1FlexGrid 列编辑器来设置:
- 在 C1FlexGrid 列编辑器中,在右侧窗格中选择 Column 6。
- 在左侧窗格中,点击 Format 属性旁边的省略号按钮来打开Format String 对话框。
- 在 Format type 中选择 Currency(货币)。
- 点击 OK 来关闭 Format String 窗口。
- 点击 OK 来关闭编辑器。
在代码中:
- Visual Basic
' 在 Sales Amount 列显示货币值。
C1FlexGrid1.Cols(6).Format = "c"
- C#
//在 Sales Amount 列显示货币值。
c1FlexGrid1.Cols[6].Format = "c";
- GetDataSource 方法创建表格中显示的数据表。该例程是非常基本的,除了检索数据的 SQL 语句。大多数人不手动编写 SQL 语句,一般使用虚拟设计器如 Visual Studio 或者 Microsoft Access 来做。
将下面的代码添加到窗体中。请注意,您可能必须稍微更改一下连接字符串,因为它引用了 NorthWind 数据库,该数据库文件可能是在您系统中不同的文件夹中:
Visual Basic
Private Function GetDataSource() As DataTable "[Quantity]*[Products].[UnitPrice] AS [Sale Amount] " & _
"INNER JOIN [Order Details] " & _ "ON Orders.OrderID = [Order Details].OrderID) " & "ON Products.ProductID = [Order Details].ProductID " & _ |
C#
private DataTable GetDataSource() "[Quantity]*[Products].[UnitPrice] AS [Sale Amount] " +
"ON Employees.EmployeeID = Orders.EmployeeID) " + "INNER JOIN [Order Details] " + Orders.OrderID = [Order Details].OrderID) " + "ON Products.ProductID = [Order Details].ProductID " + return ds.Tables[0]; |
你会看到一个普通的有前瞻性的表格,它可以让你移动列,并浏览数据。但是,这些数据没有一个明确的结构,这个表包含了几千条记录,所以想要知道得到的数据意味着什么是相当困难的。
步骤 3/4: 允许自动排序
在整理数据的第一步是排序。此外,我们想,当用户重新安排这些列时,让这些数据能够自动排序。
在用户重新安排这些列之后,C1FlexGrid 控件触发 AfterDragColumn 事件。我们将添加一个事件处理程序,以基础数据表中的数据进行排序。(如果表格处在非绑定模式,我们可以使用 Sort 方法来做到这一点。)
向窗体中添加下面的代码,用来在用户拖动列的时候排序数据记录和重建合计:
Visual Basic
Private Sub C1FlexGrid1_AfterDragColumn(ByVal sender As Object, ByVal e
As
DragRowColEventArgs) Handles C1FlexGrid1.AfterDragColumn
' 当用户拖动列的时候排序数据。
' 这将导致数据刷新,移除所有合计和触发 AfterDataRefresh 事件,并重建合计。
Dim sort As String = C1FlexGrid1.Cols(1).Name & ", " & _
C1FlexGrid1.Cols(2).Name & ", " & _
C1FlexGrid1.Cols(3).Name
Dim dt As DataTable = C1FlexGrid1.DataSource dt.DefaultView.Sort = sort
End SubC#
private void c1FlexGrid1_AfterDragColumn( object sender, DragRowColEventArgs e)
{
//当用户拖动列的时候排序数据。
//这将导致数据刷新,移除所有合计和触发 AfterDataRefresh 事件,并重建合计。
string sort = c1FlexGrid1.Cols[1].Name + ", " + c1FlexGrid1.Cols[2].Name + ", " + c1FlexGrid1.Cols[3].Name;
DataTable dt = (DataTable)c1FlexGrid1.DataSource; dt.DefaultView.Sort = sort;
}
运行该项目,并尝试通过拖动前三列的标题来重新对它们排序。每当你移动一列,数据将自动进行排序,这将使得它更加容易理解。
在下一个步骤中,我们将添加合计和一个大纲树。步骤 4/4: 添加合计和大纲树
当表格在绑定模式下使用时,任何数据源的变化都会导致表格触发
AfterDataRefresh 事件。这个事件是向表格中插入分类汇总和创建大纲树的理想代码场所。添加下面的 AfterDataRefresh 事件代码处理到窗体中:Visual Basic
Private Sub C1FlexGrid1_AfterDataRefresh(ByVal sender As Object, ByVal e
As ListChangedEventArgs) Handles C1FlexGrid1.AfterDataRefresh ' Sale Amount 的总和。
Dim totalOn As Integer = C1FlexGrid1.Cols("Sale Amount").SafeIndex Dim caption As String = "Total for {0}"
' 计算三层的总和。
C1FlexGrid1.Subtotal(AggregateEnum.Sum, 0, 1, totalOn, caption)
C1FlexGrid1.Subtotal(AggregateEnum.Sum, 1, 2, totalOn, caption) C1FlexGrid1.Subtotal(AggregateEnum.Sum, 2, 3, totalOn, caption)
' 将大纲树第二级折叠起来。
C1FlexGrid1.Tree.Show(2)
' 表格自动调整大侠以适应大纲树。
C1FlexGrid1.AutoSizeCols(1, 1, 1000, 3, 30, AutoSizeFlags.IgnoreHidden)
End SubC#
private void c1FlexGrid1_AfterDataRefresh( object sender, ListChangedEventArgs e)
{
// Sale Amount 的总和。
int totalOn = c1FlexGrid1.Cols["Sale Amount"].SafeIndex; string caption = "Total for {0}";
// 计算三层的总和。
c1FlexGrid1.Subtotal(AggregateEnum.Sum, 0, 1, totalOn, caption); c1FlexGrid1.Subtotal(AggregateEnum.Sum, 1, 2, totalOn, caption); c1FlexGrid1.Subtotal(AggregateEnum.Sum, 2, 3, totalOn, caption);
//将大纲树第二级折叠起来。
c1FlexGrid1.Tree.Show(2);
//表格自动调整大侠以适应大纲树。
c1FlexGrid1.AutoSizeCols(1, 1, 1000, 3, 30, AutoSizeFlags.IgnoreHidden);
}代码首先获得 Sale Amount 列的索引,本教程中,这个索引始终是相同的(Column 6)。按照索引通常比硬编码要好,但是,因为如果有人在 SQL 语句中添加了多个字段,该索引将会发生改变。
代码调用了 C1FlexGrid.的 Subtotal 方法来对数据进行分组并为合计添加新行。这个新行将会自动配置成大纲树的节点(它们的 IsNode 被设置为 True),以便合计和折叠起来。
试着拖动一些列,你可以清楚的看到 country、product category 或者
salesperson 的合计。当然你如果想看到更多细节的话,也可以展开树的节点。
注意,表格是可以编辑的,改变 Sale Amount 列的值将会再次触发
AfterDataRefresh 事件,并且合计也会自动的更新。
这样就结束了本教程。