65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (10投票s)

2007年12月14日

CPOL

3分钟阅读

viewsIcon

112862

downloadIcon

4856

三态复选框、用户自定义状态图像、禁用节点复选框...

Screenshot -

引言

Microsoft 在 .NET 1.1 框架中实现的 TreeView 控件支持复选框,但这些复选框仅支持两种状态:选中或未选中。

此控件建立在 TreeView 控件之上,并提供了一些可能很有用的附加功能。

  • 三态复选框,选中 / 未选中 / 不确定状态。
  • TriStateTreeView 支持所有三种状态的自定义图像。如果不使用自定义图像,则会提供默认的三态图像。自定义图像的配置方式与“ImageIndex”和“SelectedImageIndex”属性相同,因此可以通过 ImageList 属性将状态图像添加到绑定到 TreeViewImageList 中。
  • 可以按节点禁用复选框。
  • TreeView 识别两种不同类型的 TreeNode:容器和项。当子节点被选中/未选中时,它们的行为不同。

背景

此代码的一部分,主要是 wndproc 挂钩,来自本网站上找到的另一个示例。它是由 Carlos J. Quintero 开发的一个 VB.NET 示例,涉及节点字体:https://codeproject.org.cn/KB/cpp/CustomDrawTreeview.aspx。我翻译了该示例并添加了我自己的内容。感谢 Carlos 与我们分享您的代码。

使用代码

源文件中包含两个类:TriStateTreeViewTriStateTreeNode

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 属性为 CheckedIndeterminate 时返回 true。当 CheckStateUnchecked 时,该属性返回 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 日 - 第一个版本。
© . All rights reserved.