适用于 .NET 1.1 的三态 TreeView 控件






4.75/5 (10投票s)
三态复选框、用户自定义状态图像、禁用节点复选框...
引言
Microsoft 在 .NET 1.1 框架中实现的 TreeView
控件支持复选框,但这些复选框仅支持两种状态:选中或未选中。
此控件建立在 TreeView
控件之上,并提供了一些可能很有用的附加功能。
- 三态复选框,选中 / 未选中 / 不确定状态。
TriStateTreeView
支持所有三种状态的自定义图像。如果不使用自定义图像,则会提供默认的三态图像。自定义图像的配置方式与“ImageIndex
”和“SelectedImageIndex
”属性相同,因此可以通过ImageList
属性将状态图像添加到绑定到TreeView
的ImageList
中。- 可以按节点禁用复选框。
TreeView
识别两种不同类型的TreeNode
:容器和项。当子节点被选中/未选中时,它们的行为不同。
背景
此代码的一部分,主要是 wndproc
挂钩,来自本网站上找到的另一个示例。它是由 Carlos J. Quintero 开发的一个 VB.NET 示例,涉及节点字体:https://codeproject.org.cn/KB/cpp/CustomDrawTreeview.aspx。我翻译了该示例并添加了我自己的内容。感谢 Carlos 与我们分享您的代码。
使用代码
源文件中包含两个类:TriStateTreeView
和 TriStateTreeNode
。
TriStateTreeNode
类公开了一个内部属性 NodeLineType
,当 TriStateTreeView
控件即将绘制节点时会读取该属性。当某个节点禁用了复选框时,应绘制虚线来替代该复选框,就像原始 TreeView
所做的那样。
枚举 NodeLineType
属性 NodeLineType
返回 NodeLineType
类型的值,该值可以有三种不同的值:
None
- 无需绘制线条Straight
- 只需在通常绘制复选框的位置绘制一条直线WithChildren
- 需要绘制一条直线,以及一条连接到节点子节点的线
internal enum NodeLineType
{
None,
Straight,
WithChildren
}
类 TriStateTreeView
TriStateTreeView
类是从 System.Windows.Forms.TreeView
派生的,并公开了下面列出的附加属性:
UseCustomImages
- 可在设计时或运行时编辑。决定TreeView
是绘制ImageList
中配置的图像(自定义)还是默认图像。CheckedImageIndex
- 节点处于Checked
状态时显示的图像索引(必须将UseCustomImages
设置为true
)。UncheckedImageIndex
- 节点处于Unchecked
状态时显示的图像索引(必须将UseCustomImages
设置为true
)。IndeterminateImageIndex
- 节点处于Indeterminate
状态时显示的图像索引(必须将UseCustomImages
设置为true
)。
上面这四个属性都放在属性浏览器的一个类别中,名为 CheckState
。
类 TriStateTreeNode
TriStateTreeNode
类是从 System.Windows.Forms.TreeNode
派生的,并公开了下面描述的额外功能:
- 它隐藏了原始的
Checked
属性,当其CheckState
属性为Checked
或Indeterminate
时返回true
。当CheckState
为Unchecked
时,该属性返回Unchecked
。 - 附加只读属性
CheckState
,根据当前状态返回Checked/Unchecked/Indeterminate
中的一个。 - 附加读写属性
IsContainer
,用于确定TreeNode
是作为容器还是作为项进行处理。 - 附加读写属性
CheckboxVisible
,用于确定节点是否显示复选框。 - 内部属性
NodeLineType
(请参阅前面的说明)。 - 内部方法
SetCheckedState( CheckState value)
:为TriStateTreeView
类提供接口。
示例代码
private void ConfigureTreeView()
{
TriStateTreeNode folderNode = null;
TriStateTreeNode rootNode =
new TriStateTreeNode( "Home - \"CheckboxVisible = false\"." );
rootNode.CheckboxVisible = false;
rootNode.IsContainer = true;
for( int i = 1; i < 4; i++ )
{
folderNode = new TriStateTreeNode( string.Format( "Foldernode {0}," +
" can show 3 states, as shown here.", i), 0, 1 );
folderNode.IsContainer = true;
rootNode.Nodes.Add( folderNode );
}
folderNode = new TriStateTreeNode("Foldernode 4, " +
"cannot be checked, as shown here.", 0, 1);
folderNode.IsContainer = true;
folderNode.CheckboxVisible = false;
rootNode.Nodes.Add(folderNode);
TriStateTreeNode firstFolder = rootNode.FirstNode as TriStateTreeNode;
for(int i = 1; i < 3; i++)
{
TriStateTreeNode itemNode =
new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2 );
firstFolder.Nodes.Add( itemNode );
}
TriStateTreeNode secondFolder = firstFolder.NextNode as TriStateTreeNode;
for(int i = 1; i < 3; i++)
{
TriStateTreeNode itemNode =
new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2);
secondFolder.Nodes.Add( itemNode );
}
TriStateTreeNode thirdFolder = secondFolder.NextNode as TriStateTreeNode;
for(int i = 1; i < 3; i++)
{
TriStateTreeNode itemNode =
new TriStateTreeNode( string.Format( "Item node {0}", i ), 2, 2 );
thirdFolder.Nodes.Add( itemNode );
}
TriStateTreeNode fourthFolder = folderNode;
fourthFolder.CheckboxVisible = false;
for(int i = 1; i < 3; i++)
{
TriStateTreeNode itemNode =
new TriStateTreeNode( string.Format(
"Item node {0} - no checkboxes", i ), 2, 2 );
itemNode.CheckboxVisible = false;
fourthFolder.Nodes.Add( itemNode );
}
this.triStateTreeView1.SuspendLayout();
this.triStateTreeView1.Nodes.Add( rootNode );
this.triStateTreeView1.ResumeLayout();
secondFolder.FirstNode.Checked = true;
thirdFolder.Checked = true;
}
关注点
还有一些问题我希望修复,欢迎就此提供反馈。
Microsoft 有一个 TreeNodeCollectionEditor
,它允许您在设计时构建树。通常,我认为这个编辑器不太可能被使用,因为大多数 treeview 将显示动态数据,这些数据几乎从不预先配置。然而……该编辑器不适用于此 treeview,因为它添加的是 TreeNode
而不是 TriStateTreeNode
,这会禁用整个三态概念。我还没有完全弄清楚该如何解决。
我认为解决这个问题的一种方法是隐藏 TreeView
控件的 Nodes
属性,添加我们自己的 Nodes
属性,它是一个 TreeNodeCollection
风格的集合类,用于存储 TriStateTreeNode
。这,加上一个自定义的 TreeNodeCollectionEditor
,应该就能解决问题。
历史
- 2007 年 12 月 14 日 - 第一个版本。