...
固定的单元格用于显示行和列的标题信息。
你可以通过使用行和列的集合中"固定的"属性来设置固定的行和列的数目。例如,下面的代码可以创建一个具有两个固定行和无固定列的表格:
- Visual Basic
flex.Rows.Fixed = 1
_flex.Cols.Fixed = 0
- C#
flex.Rows.Fixed = 1;
_flex.Cols.Fixed = 0;
行和列的集合也包含了在表格中插入、删除和移动行和列的方法。你可以使用"条目"属性(索引)来访问在每个集合中的独立的各个元素(行和列)。
只要你愿意,你就可以在设计时通过使用 C1FlexGrid 列编辑器来设置好表格列,而不是靠编写代码来执行这一步操作。有关如何使用 C1FlexGrid 列编辑器来对列进行编辑的更多详细信息,请参阅 C1FlexGrid 列编辑器。
...
垂直的虚线显示了表格将会如何被重新调整尺寸。向左拖动指针使列宽变小;将其向右边拖动使列宽变大。当调整的操作完成,列的"宽度"属性将被调整。
在 C1FlexGrid 列编辑器中或代码中,为列指定"宽度"属性值。有关
C1FlexGrid 列编辑器的更多详细信息,请参阅"C1FlexGrid 列编辑器"。下面的代码可以设置第一列到第十列的 "宽度"的属性:
- Visual Basic
_flex.Cols(1).Width = 10
- C#
...
_flex.Cols
...
[1
...
].Width = 10;
为了防止一个特定的列被调整,请在无论是列任务菜单上,还是列编辑器或代码中,都将这一列的"允许调整"属性设置为"假"。有关列任务菜单的更多详细信息,请参阅"列任务菜单"(第 36 页)。下面的代码可以将第一列的"允许调整"属性设置为"假":
- Visual Basic
_flex.Cols(1).AllowResizing = False
- C#
...
_flex.Cols
...
[1
...
].AllowResizing = false;
单元格选择
表格中有一个光标单元格,当表格时是激活的,它会显示一个焦点矩形。当表格是可编辑的,用户可以使用键盘或鼠标来移动这个光标并且编辑单元格的内容。
请注意,Office Visual Styles 也会通过高亮显示光标单元格所在的行和列标题,来显明光标单元格的位置。要想了解更多有关设置"视觉样式"的详细信息,请参阅"自定义外观,使用视觉样式"。
你可以在代码中通过使用"行与列"属性来获取或设置当前单元格。例如,将任一属性设置为-1,可以隐藏光标。
表格支持扩展选择,单元格的矩形范围由两个对立的角落决定,即光标所在单元格和单元格选择的单元格。
请注意,Office Visual Styles 也通过高亮显示选定的单元格所在的行和列的标题来显明了扩展选择的位置。要想了解更多有关设置"视觉样式"的详细信息,请参阅"自定义外观,使用视觉样式"。
你可以在代码中通过使用"行选择"和"列选择"属性来获取或设置单元格选择,或通过使用"选择"的方法也可以。注意:当光标单元格变化了,该"选择"会自动复位。要在代码中创建扩展选项,无论是通过在"行选择"和"列选择"之前先设置"行与列"或直接使用"选择"的方法都可以。
"选择"的外观是由以下属性决定的:
定焦矩形决定了焦点矩形的类型是为了表明光标单元格而绘制的。
高亮显示决定了什么时候该"选择"应该被突出显示(通常是,当该控件有一个突出的重点时,或者从不)。
高亮和定焦都是决定了"选择"的外观的单元格样式(字体,颜色和边框)。
可供选择的类型是由"选择模式"的属性决定的。在默认情况下,表格支持常规的范围选择。你可以修改此行为来防止扩展选择,或者来按行、按列,或在列表框模式下进行选择("列表框模式"可以允许你来选择个别行)。
当使用列表框选择模式时,你可以通过使用"选择"属性来获取或设置个别行的选择状态。你还可以通过使用"选择"属性来恢复选定的行的集合。例如,下面的代码可以选择符合一个条件的所有行:
- Visual Basic
' 在"销售"列中选择多于 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)
- C#
// 在"销售"列中选择多于 8000 名销售的所有行。
_flex.SelectionMode = SelectionModeEnum.ListBox; for (int index = _flex.Rows.Fixed ; index < _flex.Rows.Count; index++)
{
if
...
(Microsoft.VisualBasic.Conversion.Val(System.Runtime.CompilerServices.Run
...
ti
...
meHelpers.GetObjectValue(_flex\[index,
...
"Sales"\]))
...
>
...
80000)
{
...
_flex.Rows
...
[index
...
].Selected = true;
}
}
Console.WriteLine("There are now {0} rows selected",
_flex.Rows.Selected.Count);
单元格区域
"单元格区域"对象可以使你将单元格的任意组合作为一个简单的单元来工作。例如,下面的代码创建了一个"单元格区域"的对象,清除了范围内的数据,并赋予了它一个自定义样式:
- Visual Basic
Dim rg As CellRange = _flex.GetCellRange(3, 3, 10, 10) rg.Data = Nothing rg.Style = _flex.Styles("MyRangeStyle")
- C#
...
CellRange rg = _flex.GetCellRange(3, 3, 10, 10); rg.Data = null; rg.Style = _flex.Styles
...
["MyRangeStyle"
...
];
"单元格区域"的对象具有可以恢复区域样式的 StyleNew 的属性, 如果存在一个,或创建了一个新的,将其分配给该区域并返回它。在你不需要对格式进行全面控制的情况下,此属性是很方便的。例如,如果你想要做的是给这个区域设定一个红色的背景,你可以编写如下代码来实现:
- Visual Basic
Dim rg As CellRange = _flex.GetCellRange(3, 3, 10, 10) rg.StyleNew.BackColor = Color.Red
- C#
CellRange rg = _flex.GetCellRange(3, 3, 10, 10); rg.StyleNew.BackColor = Color.Red;
...
为了控制单元格的内容如何被格式化,请将"格式化"属性设置到一个类似于你在.NET framework 中通过 String.Format 方法使用的格式字符串。例如,下面的代码显示了第一列的短日期和第二列的货币值:
- Visual Basic
' 短日期。
_flex.Cols(1).Format = "d"
' 货币值。
_flex.Cols(2).Format = "c"
- C#
//
...
- 短日期
_flex.Cols\[
...
- 2\].Format
...
- =
...
- "d";
//
...
- 货币值
_flex.Cols\[
...
1\].Format = "c";
单元格内容的格式也是可以通过使用格式字符串对话框在设计时就进行设置的。格式字符串对话框的访问路径有两种,一种是可通过列任务菜单。另一种是可通过 C1FlexGrid 列编辑器。在"列任务"菜单上,单击"格式字符串"中的省略号按钮。
在 C1FlexGrid 列编辑器中,在左窗格中找到"格式"属性,并单击它旁边的省略号按钮。
注意:格式字符串对话框是特定列,而且只会更改所选定的列的"格式" 属性。
你还是可以使用自定义格式,就像你在 Visual Basic "格式"功能中所使用
的一样(例如,"#,###",等等)。
检索单元格数据你可以使用索引或"获取数据"方法来检索原始的表格数据。要检索格式
过的数据,请改为使用 GetDataDisplay 的方法。例如:
- Visual Basic
' 短日期。
_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
- C#
// 短日期。
...
_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
单元格的外观
单元格的外观(对齐方式、字体、颜色、边框,等)是由"单元格样式" 对象处理的。表格有一个"样式"属性,它包含了用于设置单元格格式的所有样式的集合。这个集合有一些可以定义表格元素的外观的内置成员,如固定的和滚动的单元格,单元格选择,单元格定焦,等等。你可以更改这些样式来修改表格的外观,你也可以创建自己的自定义样式,并将它们分配给单元格,行或列。
改变内置的样式是改变表格外观的最简单的方式。例如,下面的代码可以
将所选定的部分的背景显示为红色,字体为绿色粗体:
- Visual Basic
Dim cs As CellStyle = _flex.Styles.Highlight cs.Font = New Font(_flex.Font, FontStyle.Bold) cs.ForeColor = Color.Green cs.BackColor = Color.Red
- C#
CellStyle cs = _flex.Styles.Highlight; cs.Font = new Font(_flex.Font, FontStyle.Bold); cs.ForeColor = Color.Green; cs.BackColor = Color.Red;
你还可以创建你自己的样式,并将它们分配到单元格,行和列。例如,下
面的代码可以创建一个自定义单元格样式并敬爱那个它分配给每一个第五行:
- Visual Basic
Dim Dim cs As CellStyle = _flex.Styles.Add("Fifth") cs.BackColor = Color.Gray
Dim Dim idex%
For For idex = _flex.Rows.Fixed To _flex.Rows.Count - 1 Step 5
_flex.Rows(idex).Style = cs NextNext
- C#
CellStyle cs = _flex.Styles.Add("Fifth"); cs.BackColor = Color.Gray; for (int index = _flex.Rows.Fixed ; index <= _flex.Rows.Count - 1; index += 5)
{
Wiki Markup |
---|
_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;
// 将新的样式分配到一列。
Wiki Markup |
---|
_flex.Cols\[3\].Style = _flex.Styles\["MyStyle"\]; |
// 将新的样式分配到一行。
Wiki Markup |
---|
_flex.Rows\[3\].Style = _flex.Styles\["MyStyle"\]; |
// 将新的样式分配到一个单元格区域。
Wiki Markup |
---|
CellRange rg = _flex.GetCellRange(4,4,6,6); rg.Style = _flex.Styles\["MyStyle"\]; |
...
Visual Basic
Dim cs As C1.Win.C1FlexGrid.CellStyle
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' 为"大货币值"创建一个自定义样式。
cs = _flex.Styles.Add("LargeValue") cs.Font = New Font(Font, FontStyle.Italic) cs.BackColor = Color.Gold End Sub
' 根据单元格的内容来设置其格式。
Private Sub _flex_CellChanged(ByVal sender As Object, ByVal e As
RowColEventArgs) Handles _flex.CellChanged
' 将货币值大于 50,000 的标记为"大货币值"(通过将"样式"设置为 "无"来重新设置其他的)。
Dim cs As CellStyle
If _flex(e.Row, e.Col).ToString >= 50000 Then cs = _flex.Styles("LargeValue")
_flex.SetCellStyle(e.Row, e.Col, cs)
End IfC#
CellStyle cs; private void Form1_Load(object sender, EventArgs e)
{
// 为大货币值创建一个自定义样式。
cs = _flex.Styles.Add("LargeValue"); cs.Font = new Font(Font, FontStyle.Italic); cs.BackColor = Color.Gold;
}
// 根据单元格的内容来设置其格式。
private void _flex_CellChanged( object sender, RowColEventArgs e)
{
// 将货币值大于 50,000 的标记为"大货币值"(通过将"样式"设置为
"无"来重新设置其他的)。 ifWiki Markup (Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(_flex\[e.Row, e.Col\].ToString()) >= 50000)
{Wiki Markup cs = _flex.Styles\["LargeValue"\];
_flex.SetCellStyle(e.Row, e.Col, cs);
}自绘单元格
Wiki Markup 即使 "单元格样式"对象已经通过单元格外观(背景色和前景色、对齐方式、字体、边距、边框,等等)提供了很多控件,有时这仍是不够的。你可能想使用渐变背景,或直接在单元格中画一些自定义的图形。在这些情况下,你可以使用"绘制模式"属性和"自绘单元格"事件,通过每一个单元格是如何绘制的来实现全面控制。 "绘制模式"属性决定了 "自绘单元格"事件是否被激发。该事件可以是你兼顾到每一个单元格的视觉效果。"自绘单元格"事件中的参数,允许你对所显示的数据以及用于显示数据的样式,做出更改,甚至允许你完全接管并绘制单元格中你所想要的任何东西。 你可以通过在事件处理程序中设置 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) {
// 使用渐变画笔来绘制所选定的单元格的背景。
if (_flex.Selection.Contains(e.Row, e.Col))
{
// 绘制背景。
e.Graphics.FillRectangle(m_GradientBrush, e.Bounds);
// 让表格绘制其内容。
e.DrawCell(DrawCellFlags.Content);
// 我们已完成这个单元格的绘制。
e.Handled = true;
}编辑单元格
默认情况下,C1FlexGrid 控件允许用户通过在单元格中打字来编辑单元格。你可以通过"允许编辑"属性设置为"假"来阻止用户对表格进行编辑。
你还可以通过将"允许编辑"属性设"假"来阻止用户对特定列进行编辑。
(当表格被绑定到一个数据源上,它会检测哪些列是可编辑的并自动设置"允许编辑"属性。)
要开始编辑一个单元格,用户可以:- 开始在单元格中输入。这将替换单元格原有的内容。
- 按 F2 键或 ENTER 键。这使得表格处于编辑模式下,并将当前单元格的内容放到编辑器。
- 双击一个单元格。这与按 F2 键有相同的效果,但光标会出现在被点击的单元格。
...
' 下拉列表。
_flex.Cols(1).ComboList = "Red|Green|Blue|Red|White"
' 下拉组合。
_flex.Cols(2).ComboList = "|Red|Green|Blue|Red|White"
- C#
// 下拉列表。
Wiki Markup |
---|
_flex.Cols\[1\].ComboList = "Red|Green|Blue|Red|White"; |
// 下拉组合。
Wiki Markup |
---|
_flex.Cols\[2\].ComboList = "|Red|Green|Blue|Red|White"; |
...
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");
Wiki Markup |
---|
_flex.Cols\[1\].DataType = typeof(Color); |
...
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' 按 key 排序。
Dim sl As New SortedList() sl.Add("0", "Zero") sl.Add("1", "One") sl.Add("2", "Two")
sl.Add("3", "Three")
' 保持添加顺序。
Dim ld As New Specialized.ListDictionary() ld.Add(0, "Zero") ld.Add(1, "One") ld.Add(2, "Two")
ld.Add(3, "Three") ' 任意顺序。
Dim ht As New Hashtable() ht.Add(0, "Zero") ht.Add(1, "One") ht.Add(2, "Two") ht.Add(3, "Three")
_flex.Cols(1).DataMap = sl
_flex.Cols(1).Caption = "SortedList"
_flex.Cols(2).DataMap = ld
_flex.Cols(2).Caption = "ListDictionary"
_flex.Cols(3).DataMap = ht
_flex.Cols(3).Caption = "HashTable"
End SubC#
private void Form1_Load(object sender, System.EventArgs e);
{
// 按 key 排序。
System.Collections.SortedList sl = new System.Collections.SortedList(); sl.Add("0", "Zero"); sl.Add("1", "One"); sl.Add("2", "Two");
sl.Add("3", "Three"); // 保持添加顺序。
System.Collections.Specialized.ListDictionary ld = new System.Collections.Specialized.ListDictionary(); ld.Add(0, "Zero"); ld.Add(1, "One"); ld.Add(2, "Two");
ld.Add(3, "Three");
// 任意顺序。
System.Collections.Hashtable ht = new System.Collections.Hashtable(); ht.Add(0, "Zero"); ht.Add(1, "One"); ht.Add(2, "Two"); ht.Add(3, "Three");Wiki Markup _flex.Cols\[1\].DataMap = sl;
Wiki Markup _flex.Cols\[1\].Caption = "SortedList";
Wiki Markup _flex.Cols\[2\].DataMap = ld;
Wiki Markup _flex.Cols\[2\].Caption = "ListDictionary";
Wiki Markup _flex.Cols\[3\].DataMap = ht;
Wiki Markup _flex.Cols\[3\].Caption = "HashTable";
}
此外,如果列的"数据类型"属性被设置为一个枚举,表格将自动建立并使用一个含枚举中每个值的名称的数据映射。例如,下面的代码可以创建一个包含国家的枚举。国家的值存储在表格中,向用户显示的是他们的名字:- Visual Basic
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)
{
Wiki Markup |
---|
_flex.Cols\[1\].DataType = typeof(Countries); |
...
' 建立色列。
Dim c As C1.Win.C1FlexGrid.Column = _flex.Cols(1) c.DataType = GetType(Color)
' 显示单元格按钮。
c.ComboList = "..."
- C#
// 建立色列。
Wiki Markup |
---|
Column c = _flex.Cols\[1\]; |
...
private void _flex_CellButtonClick( object sender, RowColEventArgs e)
{
// 创建"拾色器"对话框。
ColorDialog clrDlg = new ColorDialog();
// 初始化对话框。
Wiki Markup |
---|
if (_flex\[e.Row, e.Col\] == typeof(Color)) |
{
Wiki Markup |
---|
clrDlg.Color = (Color)_flex\[e.Row, e.Col\]; |
...
}
// 从对话框中获取新的颜色,并将它分配到单元格。
if (clrDlg.ShowDialog() == DialogResult.OK)
{
Wiki Markup |
---|
_flex\[e.Row, e.Col\] = clrDlg.Color; |
...
' 建立一个电话号码的编辑掩码。
_flex.Cols(1).EditMask = "(999) 999-9999"
- C#
// 建立一个电话号码的编辑掩码。
Wiki Markup |
---|
_flex.Cols\[1\].EditMask = "(999) 999-9999"; |
...
Visual Basic
Private Sub _flex_ValidateEdit(ByVal sender As Object, ByVal e As C1.Win.C1FlexGrid.ValidateEditEventArgs) Handles _flex.ValidateEdit
' 验证金额。
If _flex.Cols(e.Col).DataType Is GetType(Decimal) Then Try
Dim dec As Decimal = Decimal.Parse(_flex.Editor.Text())
If (dec < 1000) Or (dec > 10000) Then
MessageBox.Show("Value must be between 1,000 and 10,000") e.Cancel = True
End If
Catch
MessageBox.Show("Value not recognized as a Currency") e.Cancel = True
End Try
End If
End SubC#
private void _flex_ValidateEdit( object sender, ValidateEditEventArgs e)
{
// 验证金额。Wiki Markup if (_flex.Cols\[e.Col\].DataType == typeof(Decimal))
{ try
{
Decimal dec = Decimal.Parse(_flex.Editor.Text); if ( dec < 1000 || dec > 10000 ) {
MessageBox.Show("Value must be between 1,000 and 10,000"); e.Cancel = true;
}
}
catch
{
MessageBox.Show("Value not recognized as a Currency"); e.Cancel = true;
}
}
}自定义编辑器
内置的编辑器可以具备很大的灵活性和能力,但在某些情况下,你可能要使用外部控件作为专门的编辑器。例如,你可能想使用提供了一个下拉计算器的 C1NumericInput 控件来输入数字,或使用一个编辑器来从多列的列表中进行选择,或你可以用自己写的一个专门的控件来编辑你的业务对象。
从基本的"控件"类型派生出的任何控件都可以作为一个基本的表格编辑
器使用。实现了 IC1EmbeddedEditor 接口(在 C1.Common.dll 的定义)的控件可
以用表格提供更好的整合和更先进的功能。有关 IC1EmbeddedEditor 接口的更多详细信息,请参阅"编辑属性"。
要将一个控件作为自定义编辑器来使用,所有你必须要做的就是使用其
"编辑"属性将控件的一个实例与一个表格列或一个样式关联到一起。你可以在设计器(使用列编辑器)或在代码中实现这步操作。在此之后,表格将自动使用该控件。
要在设计时定义自定义编辑器,先要将编辑器控件的一个实例添加到窗
体,然后从 C1FlexGrid 任务菜单上选择设计器来打开 C1FlexGrid 列编辑器。选择应使用自定义编辑器的列,并将其编辑器的属性设置为新的编辑器控件的名称。
例如,要将 NumericUpDown 控件作为一个表格编辑器使用,请按照下列步骤操作:
...
private void Form1_Load(object sender, System.EventArgs e)
{
// 创建自定义编辑器。
NumericUpDown editor = new NumericUpDown();
editor.BorderStyle = BorderStyle.None;
// 将自定义编辑器分配到表格。
Wiki Markup |
---|
_flex.Cols\[1\].Editor = editor; |
...
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load Dim i%
' 初始化该控件。
_flex.Styles.Normal.WordWrap = True
_flex.Cols.Count = 9
_flex.Rows.Fixed = 2
_flex.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.FixedOnly
' 创建行标题。
_flex.Rows(0).AllowMerging = True
' 合并含有相同内容的四个单元格。
Dim rng As C1.Win.C1FlexGrid.CellRange = _flex.GetCellRange(0, 1, 0, 4) rng.Data = "North"
' 合并含有相同内容的四个单元格。
rng = _flex.GetCellRange(0, 5, 0, 8) rng.Data = "South"
For i = 1 To 4
_flex(1, i) = "Qtr " & i
_flex(1, i + 4) = "Qtr " & i Next
' 创建列标题。
_flex.Cols(0).AllowMerging = True
' 合并含有相同的内容的两个单元格。
rng = _flex.GetCellRange(0, 0, 1, 0)
rng.Data = "Sales by Product"
' 对齐单元格和自动调整单元格大小。
_flex.Styles.Fixed.TextAlign =
C1.Win.C1FlexGrid.TextAlignEnum.CenterCenter
_flex.AutoSizeCols(1, _flex.Cols.Count - 1, 10)C#
private void Form1_Load(System.object sender, System.EventArgs e)
{
int i;
// 初始化该控件。
_flex.Styles.Normal.WordWrap = true;
_flex.Cols.Count = 9;
_flex.Rows.Fixed = 2;
_flex.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.FixedOnly;
// 创建行标题。Wiki Markup _flex.Rows\[0\].AllowMerging = true;
// 合并含有相同内容的四个单元格。
C1.Win.C1FlexGrid.CellRange rng = _flex.GetCellRange(0, 1, 0, 4); rng.Data = "North";
// 合并含有相同内容的四个单元格。
rng = _flex.GetCellRange(0, 5, 0, 8); rng.Data = "South";
for ( i = 1 ; i <= 4; i++)
{Wiki Markup _flex\[1, i\] = "Qtr " + i;
Wiki Markup _flex\[1, i + 4\] = "Qtr " + i;
}
// 创建列标题。Wiki Markup _flex.Cols\[0\].AllowMerging = true;
// 合并含有相同的内容的两个单元格。
rng = _flex.GetCellRange(0, 0, 1, 0);
rng.Data = "Sales by Product";
// 对齐单元格和自动调整单元格大小。
_flex.Styles.Fixed.TextAlign =
C1.Win.C1FlexGrid.TextAlignEnum.CenterCenter;
_flex.AutoSizeCols(1, _flex.Cols.Count - 1, 10);
}以下是结果:
合并后的数据视图
当表格被绑定到一个数据源时,单元格合并会以同样的方式进行。下面的代码显示了一个在设计时表格绑定到数据源的例子。有关绑定到一个数据源的更多详细信息,请参阅"绑定到一个数据源"(第 95 页)。Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load Dim i%
' 设置单元格合并。
_flex.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.RestrictCols
For i = _flex.Cols.Fixed To _flex.Cols.Count - 1
_flex.Cols.AllowMerging = True
Next
End Sub- C#
...
' 设置分类汇总的样式。
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
- C#
// 设置分类汇总的样式。
Wiki Markup |
---|
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; |
...
private void AddDirectory(string dir, int level)
|
...
的。如果你的数据源在设计时是可用的,你可以使用 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;
// 为"总价"列设置格式
Wiki Markup |
---|
_flex.Cols\["ExtendedPrice"\].Format = "n2"; |
...
// 在给定列上将插入的同一个给定级别的节点分组
|
...
// unbind and re-bind grid in order to reset everything void ResetBinding()
|
...
// 在一个给定层级的每个节点添加分类汇总
|
...
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");
// 隐藏我们分过组的那些列
// (他们只有在树型图节点上已经出现过的那些重复的值)
// (但不要使它们不可见,这可能会隐藏节点的文本)
Wiki Markup |
---|
_flex.Cols\["Country"\].Width = 0; |
...
"节点"类提供了许多可以用来创建和管理大纲树型图的方法和属性。这些方法和属性中的许多都是基于标准的 TreeView 对象模型,因此他们应该熟悉大多数的开发者。
为了获得一个"节点"对象,你可以:
使用 Rows.InsertNode 方法的返回值:
Var node = _flex.Rows.InsertNode(index, level);
或者,你可以用行的节点属性来在现有的一行检索节点:
Wiki Markup |
---|
Var node = _flex.Rows\[index\].IsNode |
...
Visual Basic
Private Sub _btnData_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles _btnData.Click
' 准备好 DataReader。
Dim strConn As String = "data source=MYMACHINE;initial catalog=Northwind;"
Dim myConn As New SqlClient.SqlConnection(strConn)
Dim myCMD As New SqlClient.SqlCommand("SELECT * FROM Employees", myConn) myConn.Open()
Dim myReader As SqlClient.SqlDataReader = myCMD.ExecuteReader()
' 从 DB 模式来建立表格结构。
Dim dt As DataTable = myReader.GetSchemaTable()
_flex.Cols.Count = 1
Dim dr As DataRow
For Each dr In dt.Rows
Dim c As C1.Win.C1FlexGrid.Column = _flex.Cols.Add() c.Caption =(c.Name <= CStr(dr("ColumnName")))
c.DataType = CType(dr("DataType"), Type) Next dr
' 填充表格。
_flex.Rows.Count = 1
Dim row As Integer = 1
Dim cols As Integer = dt.Columns.Count
Dim v As Object() = CType(Array.CreateInstance(GetType(Object), cols), Object())
While myReader.Read() myReader.GetValues(v)
_flex.AddItem(v, row + 1, 1) End While
' 清理。
_flex.AutoSizeCols() myReader.Close() myConn.Close()C#
private void _btnData_Click(object sender, System.EventArgs e)
{
// 准备好 DataReader。
string strConn = "data source=MYMACHINE;initial catalog=Northwind;";
System.Data.SqlClient.SqlConnection myConn = new
System.Data.SqlClient.SqlConnection(strConn);
System.Data.SqlClient.SqlCommand myCMD = new
System.Data.SqlClient.SqlCommand("SELECT * FROM Employees", myConn); myConn.Open();
System.Data.SqlClient.SqlDataReader myReader = myCMD.ExecuteReader();
// 从 DB 模式来建立表格结构。
DataTable dt = myReader.GetSchemaTable();
_flex.Cols.Count = 1; foreach (DataRow dr in dt.Rows)
{
Column c = _flex.Cols.Add();Wiki Markup c.Caption = c.Name = (string)dr\["ColumnName"\];
Wiki Markup c.DataType = (Type)dr\["DataType"\];
// 填充表格。Wiki Markup _flex.Rows.Count = 1; int row = 1; int cols = dt.Columns.Count; object\[\] v = (object\[\])Array.CreateInstance(typeof(object), cols); while (myReader.Read())
{
myReader.GetValues(v);
_flex.AddItem(v, row++, 1);
}
// 清理。
_flex.AutoSizeCols(); myReader.Close(); myConn.Close();
}打印表格
使用"打印表格"方法来打印表格的内容。该方法具有可以让你选择缩放模式,是否显示打印/预览对话框,设置页眉和页脚,等等的参数。
"打印参数"属性可以公开额外的打印性能,如字体,使用页眉和页脚,而一个.NET Framework "打印文档"对象可以用来选择打印机,纸张大小和方向,页边距等。
下面的代码使用了"打印参数"属性来设置页面方向、页边距、页眉和页脚的字体。然后它调用"打印表格"方法来显示打印预览对话框窗口:Visual Basic
' 获取表格的"打印文档"对象。
Dim pd As Printing.PrintDocument pd = _flex.PrintParameters.PrintDocument()
' 设置页面(横向打印,左边页边距 1.5")。
With pd.DefaultPageSettings
.Landscape = True
.Margins.Left = 150 End With
' 设置页眉和页脚的字体。
_flex.PrintParameters.HeaderFont = New Font("Arial Black", 14,
FontStyle.Bold)
_flex.PrintParameters.FooterFont = New Font("Arial Narrow", 8,
FontStyle.Italic)
' 预览表格。
_flex.PrintGrid("C1FlexGrid",
C1.Win.C1FlexGrid.PrintGridFlags.FitToPageWidth +
C1.Win.C1FlexGrid.PrintGridFlags.ShowPreviewDialog, "C1FlexGrid" + Chr(9)
+- C#
...
正如我们前面提到的这个文件,设置表格的"允许过滤"属性为"真",这足以让所有的列进行列过滤。然而,在许多情况下,你可能需要更精细的过滤控制。这可以通过修改个别列的"允许过滤"和"过滤"属性来实现。例如,下面的代码使能够启用过滤,但对过滤字符串类型的列进行了限制:
// 绑定和配置表格
flex.DataSource = dtProducts;
Wiki Markup |
---|
_flex.Cols\["UnitPrice"\].Format = "#,###.00"; |
...
// 创建一个新的"条件过滤器"
|
...
// 在应用过滤器之前暂停绘制
|
...
既然定时器已经被配置好了,所有我们需要做的就是在计时器滴答计时时来创建和应用过滤器:
// 在计时器滴答计时时应用过滤器
|
...