【问题标题】:How to show multiple check boxes in a TreeView in C#?如何在 C# 的 TreeView 中显示多个复选框?
【发布时间】:2015-04-23 00:27:44
【问题描述】:

我知道如何在 TreeView 中为每个 TreeNode 显示一个 CheckBox。 我想在 TreeView 中为每个 TreeNode 显示 3 个 CheckBox。 这样做的原因是我的程序中有3个图表,每个TreeNode代表一个不同的系列。我想让用户选择在他们喜欢的任何图表上显示每个系列。

这(或类似的)可能吗?提前致谢。

【问题讨论】:

  • winforms? wpf ?或使用任何第三方树视图?
  • 这在 wpf 中非常容易。在winforms中,我能想到的唯一方法是ownerdraw树视图并构建自己的复选框。

标签: c# winforms checkbox treeview


【解决方案1】:

您需要拥有一个TreeView。不完全是所有者绘制控件的最简单示例,但仍然不太难。

这是一个示例截图:

首先我们创建简单的TreeNode 子类来保存额外的数据:

public class TreeNode3 : TreeNode
{
    public string Label { get; set; }
    public bool Check1 { get; set; }
    public bool Check2 { get; set; }
    public bool Check3 { get; set; }

    public new string Text
    {
        get { return Label; }
        set { Label = value; base.Text = ""; }
    }

    public TreeNode3()   { }

    public TreeNode3(string text)   { Label = text; }

    public TreeNode3(string text, bool check1, bool check2, bool check3)
    {
        Label = text;
        Check1 = check1; Check2 = check2; Check3 = check3;
    }

    public TreeNode3(string text, TreeNode3[] children)
    {
        Label = text;
        foreach (TreeNode3 node in children) this.Nodes.Add(node);
    }
}

请注意,我隐藏了原始文本并基本上将其替换为字符串变量标签。我避免使用Tag,所以你仍然可以自己使用它。我还没有实现所有的构造函数。如果您需要ImageLists,您可能需要添加ImageIndices

现在是TreeView 本身:

using System.Windows.Forms.VisualStyles;
//..

public partial class UcTreeView : TreeView
{
    [DisplayName("Checkbox Spacing"),  CategoryAttribute("Appearance"),
     Description("Number of pixels between the checkboxes.")]
    public int Spacing { get; set; }

    [DisplayName("Text Padding"), CategoryAttribute("Appearance"), 
     Description("Left padding of text.")]
    public int LeftPadding { get; set; }



    public UcTreeView()
    {
        InitializeComponent();
        DrawMode = TreeViewDrawMode.OwnerDrawText;
        HideSelection = false;    // I like that better
        CheckBoxes = false;       // necessary!
        FullRowSelect = false;    // necessary!
        Spacing = 4;              // default checkbox spacing
        LeftPadding = 7;          // default text padding
    }

    public TreeNode3 AddNode(string label, bool check1, bool check2, bool check3)
    {
        TreeNode3 node = new TreeNode3(label, check1, check2, check3);
        this.Nodes.Add(node);
        return node;
    }

    private  Size glyph = Size.Empty;

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        TreeNode3 n = e.Node as TreeNode3;
        if (n == null) { e.DrawDefault = true; return; }

        CheckBoxState cbsTrue = CheckBoxState.CheckedNormal;
        CheckBoxState cbsFalse = CheckBoxState.UncheckedNormal;

        Rectangle rect = new Rectangle(e.Bounds.Location, 
                             new Size(ClientSize.Width, e.Bounds.Height));
        glyph = CheckBoxRenderer.GetGlyphSize(e.Graphics, cbsTrue );
        int offset = glyph.Width * 3 + Spacing * 2 + LeftPadding;

        if (n.IsSelected)
        {
            e.Graphics.FillRectangle(SystemBrushes.MenuHighlight ,rect);
            e.Graphics.DrawString(n.Label, Font, Brushes.White, 
                                  e.Bounds.X + offset, e.Bounds.Y);
        }
        else
        {
            CheckBoxRenderer.DrawParentBackground(e.Graphics, e.Bounds, this);
            e.Graphics.DrawString(n.Label, Font, Brushes.Black, 
                                  e.Bounds.X + offset, e.Bounds.Y);
        }

        CheckBoxState bs1 = n.Check1 ? cbsTrue : cbsFalse;
        CheckBoxState bs2 = n.Check2 ? cbsTrue : cbsFalse;
        CheckBoxState bs3 = n.Check3 ? cbsTrue : cbsFalse;

        CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 0).Location, bs1);
        CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 1).Location, bs2);
        CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 2).Location, bs3);

    }

    protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
    {
        Console.WriteLine(e.Location + " bounds:"  + e.Node.Bounds);

        TreeNode3 n = e.Node as TreeNode3;
        if (e == null) return;

        if      (cbx(n.Bounds, 0).Contains(e.Location)) n.Check1 = !n.Check1;
        else if (cbx(n.Bounds, 1).Contains(e.Location)) n.Check2 = !n.Check2;
        else if (cbx(n.Bounds, 2).Contains(e.Location)) n.Check3 = !n.Check3;
        else
        {
            if (SelectedNode == n && Control.ModifierKeys == Keys.Control)
                 SelectedNode = SelectedNode != null ? null : n;
            else SelectedNode = n;
        }

        Console.WriteLine(" " + n.Check1 + " " + n.Check2 +" " + n.Check3 );

        Invalidate();

    }


    Rectangle cbx(Rectangle bounds, int check)
    {
        return new Rectangle(bounds.Left + 2 + (glyph.Width + Spacing) * check, 
                             bounds.Y + 2, glyph.Width, glyph.Height);
    }

}

几点说明:

  • 树不支持LabelEditing。可行,但又是一罐蠕虫..
  • 树不支持 FullrowSelect 为真,但实际上它仍然有效..
  • ImageListStateImageList 应该可以使用,但需要在添加节点后设置索引。
  • 不要将CheckBoxes 属性设置为true!所有三个CheckBoxes 都是虚拟的,您可以在将节点转换为TreeNode3 作为其Check1..Check3 属性后访问它们!
  • 我没有实现三态复选框。您可以将布尔值更改为可为空,然后在单击和绘制事件中添加所需的代码。
  • 我在代码中留下了几个Console.WriteLines 以便更好地测试..

更新我添加了SpacingPadding 属性和一些构造函数。 现在设置示例的表单代码看起来很正常:

ucTreeView1.Nodes.Add(new TreeNode3("Bauhaus", true, true, false));
TreeNode3 aNode = ucTreeView1.AddNode("Beatles", true, true, false);
ucTreeView1.Nodes.Add(new TreeNode3("Blur", true, true, false));
ucTreeView1.Nodes.Add(new TreeNode3("Byrds", true, true, false));
ucTreeView1.Nodes.Add(new TreeNode3("Bee Gees", new TreeNode3[]{
    new TreeNode3("Barry", true, false, false),
    new TreeNode3("Robin"),  
    new TreeNode3("Maurice")} ));

TreeNode3 aNodeA = new TreeNode3("John",   true, true,  false);
TreeNode3 aNodeB = new TreeNode3("Paul",   true, true,  true);
TreeNode3 aNodeC = new TreeNode3("George", true, false, true);
TreeNode3 aNodeD = new TreeNode3("Ringo",  true, false, false);

aNode.Nodes.Add(aNodeA);
aNode.Nodes.Add(aNodeB);
aNode.Nodes.Add(aNodeC);
aNode.Nodes.Add(aNodeD);

【讨论】:

    【解决方案2】:
    I have applied treeview nodes populated with multiple childs in one of my work, hence it can give you an idea: 
    int k=0,L=0,totalNode=0;
                for (int j = 0; j < ((object[])(row[0, 0])).Length; j++) {
    
                    TreeNode root = new TreeNode();  // Creating new root node
                    root.Text = ((object[])(row[0, 1]))[j].ToString()+" "; 
                    root.Tag = ((object[])(row[0, 0]))[j].ToString();
                    int projectID = Convert.ToInt32(root.Tag);
                    treeView1.Nodes.Add(root); //Adding the node
                    totalNode++;
    
                    TaskDataHandler taskData = new TaskDataHandler();
                    object[,] arrTask = new object[1, 2];
                    arrTask = taskData.GetTaskData(xdoc, AppVariable.apiToken, projectID);
                    for (int i = 0; i < ((object[])(arrTask[0, 0])).Length; i++) {
                        totalNode++;
                        TreeNode child = new TreeNode(); // creating child node
                        child.Text = ((object[])(arrTask[0, 1]))[i].ToString() + " ";
                        child.Tag = ((object[])(arrTask[0, 0]))[i].ToString();
                        root.Nodes.Add(child); // adding child node
                    }
    
                }
    

    点击此链接以获得在链接中的节点中添加复选框的想法: https://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.checkboxes%28v=vs.140%29.aspx

    【讨论】:

      猜你喜欢
      • 2014-04-16
      • 2021-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-06
      • 2011-08-30
      • 1970-01-01
      • 2017-07-26
      相关资源
      最近更新 更多