How to show multiple check boxes in a TreeView in

2019-04-15 10:45发布

I know how to show a single CheckBox for each TreeNode in a TreeView. I would like to show 3 CheckBoxes for each TreeNode in a TreeView. The reason for this is that there are 3 charts in my program, and each TreeNode represents a different series. I would like to give the user the option of displaying each series on whichever chart they like.

Is this (or something similar) possible? Thanks in advance.

2条回答
贪生不怕死
2楼-- · 2019-04-15 11:26
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
                }

            }

Follow this link to get an idea to add checkbox in a node from the link: https://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.checkboxes%28v=vs.140%29.aspx

查看更多
Juvenile、少年°
3楼-- · 2019-04-15 11:48

You will need to owner-draw a TreeView. Not exactly the simplest example of owner-drawing a Control but still not too hard.

Here is an example screenshot:

enter image description here

First we create simple TreeNode subclass to hold the extra data:

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);
    }
}

Note that I hide the original Text and basically replace it by a string variable Label. I avoid using the Tag so you can still make use of it yourself.. I have not implemented all constructors. If you need ImageLists you may want to add those with the ImageIndices.

Now for the TreeView itself:

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);
    }

}

A few notes:

  • The tree does not support LabelEditing. Doable but another can of worms..
  • The tree does not support FullrowSelect to be true but actually it is in effect anyway..
  • You should be able to use ImageList and StateImageList but need to set the indices after the nodes are added.
  • Do not set the CheckBoxes property to true! All three CheckBoxes are virtual and you access them after casting the nodes to TreeNode3 as its Check1..Check3 properties!
  • I have not implemented 3-State CheckBoxes. You could change the bools to be nullable and then add the code needed in the click and draw events.
  • I have left a few Console.WriteLines in the code for better testing..

Update I have added a Spacing and Padding property and a few constructors. Now the form code that sets up the example looks pretty normal:

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);
查看更多
登录 后发表回答