ComponentOne FlexGrid for WinForms 中文版快速入门(7)—概述和汇总数据(下)

大纲树型图

大纲树型图与你在一个普通的“树型视图”控件中看到的非常相似。它显示了一个在每个节点行旁边有折叠或 扩展的图标的缩进结构,以便用户可以展开和折叠大纲以看到理想层级的细节。

如果您是第一次阅读本系列文章,建议您阅读:

大纲树型图可以在任何列中显示,这取决于由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的方法来显示所有零级节点(在这种情况下,就是城市那一层)并隐藏所有的细节。

“树”的属性使一个引用返回到公开了可以用于定制大纲树型图的几种方法和属性的GridTree对象,。其中主要的一些列举如下:

· :获取或设置包含了大纲树型图的列的索引。将此属性设置为-1可以导致用户看不到大纲树型图。

· 缩进:以像素为单位,在相邻的节点层级之间,获取或设置缩进。更高的缩进层级会导致树变得越来越宽。

· 样式:获取或设置即将显示的大纲树型图的样式。用这个属性来判断该树型图是否应包括顶部的一个按钮栏,来允许用户折叠/展开整个树型图,来判断线条和(或)符号是否应被显示,来判断线条是否应被显示既连接到了数据行又连接到了节点行。

· 线条颜色:获取或设置树型图连接线的颜色。

· 线条样式:获取或设置树型图连接线的样式。

例如,通过改变上面的代码来包含这两个线条:

// 显示大纲树型图

_flex.Tree.Column = 0;

_flex.Tree.Style = TreeStyleFlags.CompleteLeaf;

_flex.Tree.LineColor = Color.White;

_flex.Tree.Indent = 30;

大纲树型图会改变如下:

image

请注意标有“1”,“2”和“*”的、在左上角单元格上的按钮。点击这些按钮,会导致整个树型图折叠或展开到相应的级别。还请注意,更宽的缩进和线条将树型图既连接到普通行(“Anne Dodsworth”)又连接到节点行。

1.1.2 添加分类汇总

到目前为止,我们已经介绍了节点行和大纲树型图的创建。然而,为了使大纲真正有用,节点行应该包括它们所包含的数据的汇总信息。

如果你使用C1FlexGrid.Subtotal方法来创建一个大纲树型图,然后分类汇总将会被自动添加。这将在后面的章节中描述。

如果你像上面所描述的使用Rows.InsertNode方法来创建大纲树型图,那么你应该使用C1FlexGrid。总结用来计算每个行的分组中的分类汇总方法,并且将结果直接插入节点行。

下面列举出来的C1FlexGrid.Subtotal方法演示了如何做到这一点:

// 在一个给定层级的每个节点添加分类汇总

void AddSubtotals(int level, string colName)

{

// 获取我们将要进行汇总的列

int colIndex = _flex.Cols.IndexOf(colName);

// 为找到合适层级的节点对行进行扫描

for (int r = _flex.Rows.Fixed; r < _flex.Rows.Count; r++)

{

if (_flex.Rows[r].IsNode)

{

var node = _flex.Rows[r].Node;

if (node.Level == level)

{

// 找到一个节点,计算总价的总和

var range = node.GetCellRange();

var sum = _flex.Aggregate(AggregateEnum.Sum,

range.r1, colIndex, range.r2, colIndex,

AggregateFlags.ExcludeNodes);

// 在表格上显示总和

// (将自动使用列格式)

_flex[r, colIndex] = sum;

}

}

}

}

添加分类汇总”方法可以扫描所有表格中的行来寻找节点行。当一个理想层级的节点行被发现时, 该方法可以使用“获取单元格区域”的方法来检索节点的子行。然后它使用C1FlexGrid.Aggregate方法来计算整个范围内目标列中值的总和。聚合的调用包括一个可以避免重复计算的现有节点的“排除节点”的标志。一旦小计已经被计算,它就会与通常的_flex[行,彩色]索引一起被分配到节点行的单元格。

请注意,这并不会以任何方式影响到数据源,因为节点行并没有绑定到数据。还要注意,该方法可以被用来将多个汇总添加到每个节点行。在这个例子中,我们将增加数量和总价列的汇总。除了总金额,你还可以添加其他的集合值,比如平均值,最高值,最低值等等。

现在我们可以用这种方法来创建一个包括节点行、大纲树型图以及分类汇总的完整的大纲:

void _btnTreeCountryCity_Click(object sender, EventArgs e)

{

using (new DeferRefresh(_flex))

{

// 恢复原来的排序(按照国家、城市、销售人员)

ResetBinding();

// 按照国家、城市分组

GroupBy("Country", 0); // group by country (level 0)

GroupBy("City", 1); // group by city (level 1)

// 添加每个国家、城市的总数

AddSubtotals(0, "ExtendedPrice"); // extended price per

country (level 0)

AddSubtotals(0, "Quantity"); // quantity per country

(level 0)

AddSubtotals(1, "ExtendedPrice"); // extended price per city

(level 1)

AddSubtotals(1, "Quantity"); // quantity per city (level

1)

// 显示大纲树型图

_flex.Tree.Column = 0;

_flex.AutoSizeCol(_flex.Tree.Column);

_flex.Tree.Show(1);

}

}

如果你现在运行该项目,你会看到一个由节点行组成的树型图,其中显示了每个国家和城市的销售总数量和金额。虽然这非常好,但还是有一个小问题。如果你展开任何节点行,你会看到大量的重复值。一个给定的城市节点下的所有行都有相同的国家和城市:

image

这是正确的,但它同时也是一种 屏幕实际使用面积的浪费。消除这些重复的值是很容易的;所有你所需要做的只是将正在被分组的列的宽度设置为零。然而,当你这样做时,你应该记得将表格的“允许合并”属性设置为“节点”,以便使分配给节点行的文本可以溢出到可见列。(另一种选择是将节点的文本指定到第一个可见列,但合并通常是一个更好的解决方案,因为它可以让你在节点行使用更长的文本)。

下面是修改后的代码和最终结果:

void _btnTreeCountryCity_Click(object sender, EventArgs e)

{

using (new DeferRefresh(_flex))

{

// 恢复原来的排序(按照国家、城市、销售人员)

ResetBinding();

// 按照国家、城市来分组

GroupBy("Country", 0); // group by country (level 0)

GroupBy("City", 1); // group by city (level 1)

// 隐藏我们分过组的那些列

// (他们只有在树型图节点上已经出现过的那些重复的值)

// (但不要使它们不可见,这可能会隐藏节点的文本)_flex.Cols["Country"].Width = 0;

_flex.Cols["City"].Width = 0;

// 允许节点的内容溢出到下一个单元格

_flex.AllowMerging = AllowMergingEnum.Nodes;

// 添加每个国家和城市的总数

AddTotals(0, "ExtendedPrice"); // extended price per country

(level 0)

AddTotals(0, "Quantity"); // quantity per country (level

0)

AddTotals(1, "ExtendedPrice"); // extended price per city

(level 1)

AddTotals(1, "Quantity"); // quantity per city (level 1)

// 显示大纲树型图

_flex.Tree.Column = 0;

_flex.AutoSizeCol(_flex.Tree.Column);

_flex.Tree.Show(1);

}

}

image

 

 

 

 

 

 

 

 

 

国家城市列现在是不可见的,但它们的值仍然出现在节点行。折叠起来的的树型图可以显示每个国家和城市的总数。

1.1.3 使用分类汇总方法

在前面我们曾经提到,你也可以使用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);

}

}

分类汇总的方法非常方便和灵活。它包含多个重载,能够使你明确应该对哪些列进行分组并按照索引或名称来​​合计总数,是否包括它插入节点行的标题,以及如何进行分组等等。下面的摘要介绍了可用的重载:

1. SubtotalAggregateEnum aggType

该方法的这个版本只有一个聚合类型作为一个参数。只有消除现有的分类汇总,然后再插入新的,它才是有用的。在这种情况下, aggType参数要设置到AggregateEnum.Clear。

2. Subtotal(AggregateEnum aggType, intgroupBy, inttotalOn)

Subtotal(AggregateEnum aggType, string groupBy, string totalOn)

这都是最常用的重载。参数都是聚合类型的,可以用来插入和分组和计算总数的列。列是可以通过索引或名称来引用的。而后者则是我们在上面的例子中使用过的。

3. Subtotal(AggregateEnum aggType, int groupBy, int totalOn, string caption)

Subtotal(AggregateEnum aggType, string groupBy, string totalOn, string caption)

这些重载添加了一个额外的标题参数。标题参数明确了被添加到新的节点行的文本,以确定要进行分组的值。默认情况下,要分组的值会显示出来,所以如果你是按国家分组的,节点行会显示“阿根廷”,“巴西”,等等。如果你设置的标题参数为字符串,如“国家:{0}”,那么该节点的行会相应地显示“国家:阿根廷”来代替。

4. Subtotal(AggregateEnum aggType, int groupFrom, int groupTo, int totalOn, string caption)

Subtotal(AggregateEnum aggType, string groupFrom, string groupTo, string totalOn, string caption)

这些重载将groupby函数参数分成了两个:groupFrom和groupTo。在默认情况下,无论什么时候GroupBy的值或以往的任何列发生了变化,分类汇总的方法都可以插入一个节点行。例如,即使GroupBy列的值是相同的,如果某一行在“城市”这一列有与前行中相同的值,但在 “国家”一栏有不同的值,那么分类汇总的方法也会认为行应该在不同的分组里面并且插入一个新的节点行。这些聚合使你撤销该行为,并且指定在确定一组时应该考虑的列的范围。

1.1.4 大纲维护

到目前为止,我们已经讨论了如何使用高级别的C1FlexGrid. Subtotal方法以及较低级别的Rows.InsertNodeAggregate方法来创建总计包含树型图和总计的大纲。

在这一点上,重要的是要记住,大纲树型图是基于数据而创建的,但是它不被任何方式约束,并且当表格或数据有变化时它不能自动维持现状。例如,如果用户在“总价”这一列修改了一个值,则分类汇总不会进行自动更新。如果用户将表格进行排序,那么数据将会被刷新,且分类汇总会消失。

有两种常见的方式可以用来维持大纲:

· 防止用户做任何将会使大纲无效的更改。这是最简单的选择。你可以设置表格的的“允许编辑”、“允许拖动”和“允许排序”属性为“假”,并且阻止任何会影响到大纲的更改。

· 当数据或表格有变化时更新大纲时。你会附加表格的“数据刷新后”、“排序后”和“编辑后”事件的处理程序,并重新生成合适的大纲。

选项二通常是更有趣的,因为它提供了一个快捷而且简单的动态数据分析工具。这种方法是C1FlexGrid提供的“分析”示例来说明的。该示例创建了一个初始大纲,并允许用户对列进行重新排序。当列的顺序发生变化时,该示例自动对数据进行重新排序,并重新创建大纲。用户可以方便地创建简单的报告,来按国家、按产品、按销售人员等显示销售。

1.1.5 使用节点类

“节点”类提供了许多可以用来创建和管理大纲树型图的方法和属性。这些方法和属性中的许多都是基于标准的TreeView对象模型,因此他们应该熟悉大多数的开发者。

为了获得一个“节点”对象,你可以:

使用Rows.InsertNode方法的返回值:

var node = _flex.Rows.InsertNode(index, level);

或者,你可以用行的节点属性来在现有的一行检索节点:

var node = _flex.Rows[index].IsNode

? _flex.Rows[index].Node

: null;

无论哪种方式,一旦你有了一个“节点”对象,你就可以使用以下属性和方法来操作它:

· 等级:在大纲树型图中获取或设置节点级别。

· 数据:在单元格中获取或设置由Node.RowTree.Column定义的值。

· 图片:在单元格中获取或设置由Node.RowTree.Column定义的图像。

· 选中:获取或设置由Node.RowTree.Column定义的单元格的选中状态。

· 折叠/扩展:获取或设置节点的折叠/展开状态。

你还可以使用下列方法来探讨的大纲结构:

· 获取单元格区域:获取单元格区域的对象,它描述了属于这个节点的行的范围。

· 子节点:获取此节点下的子节点的数目。

· 节点:获取一个节点的包含此节点的子节点数组。

· 获取节点:获取与这个节点有一个给定关系的节点(父母,第一个孩子,下一个兄弟,等等)。

上面的讨论集中在绑定的情况下,即表格连接到提供数据的数据源的地方。你还可以创建绑定场景中的树型图和大纲。在这种情况下,事情其实比较简单,因为你可以通过将“是节点”属性设置为“真”来将任何一个节点变成一个节点行。

如果表格是未绑定的,它拥有所有显示的数据,并且当一个数据源拥有这些数据时,你做的是不可能的事情。例如,你可以像C1FlexGrid提供的“树型图节点”样品所显示的那样,使用Move方法来移动树型图周围的节点。

使用一个未绑定的表格中的节点与使用常规的“树型视图”控件的节点是非常相似的。

posted @ 2012-12-13 14:48  葡萄城开发工具  阅读(1965)  评论(0编辑  收藏  举报