Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
534 views
in Technique[技术] by (71.8m points)

c# - Aftercheck and AfterSelect events in Treeview in Windows Forms

Im setting up a new Form and Im having some issuis with the TreeViewNodes checking and uncheking the childs. Its easier to see the problem in this short clip

Normally it works properly but sometimes it gets stuck (I think there is a conflict with selection but Im not sure) and the methods arent applied properly.

I have this methods to check and uncheck the childs:

private void Treeview_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (e.Action != TreeViewAction.Unknown)
        if (e.Node.Checked)
        {
            CheckAll(e.Node.Nodes);
        }
        if (e.Node.Checked == false)
        {
            Uncheckall(e.Node.Nodes);
        }
}

public void Uncheckall(TreeNodeCollection nodes)
{
    foreach (TreeNode node in nodes)
    {
        node.Checked = false;
        foreach (TreeNode node1 in node.Nodes)
        {
            node1.Checked = false;
            foreach (TreeNode node2 in node1.Nodes)
            {
                node2.Checked = false;
            }
        }
    }
}


public void CheckAll(TreeNodeCollection nodes)
{
    foreach (TreeNode node in nodes)
    {
        node.Checked = true;
        foreach (TreeNode node1 in node.Nodes)
        {
            node1.Checked = true;
            foreach (TreeNode node2 in node1.Nodes)
            {
                node2.Checked = true;
            }
        }
    }
}

And I have tried to make the selection null:

private void TreeView_Select(object sender, TreeViewEventArgs e)
{
    TreeView.SelectedNode = null;
}

But the problem remains. Any ideas? Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The answers of the question that I mentioned in my comment shows us different ways regarding how to iterate through TreeView nodes. To do that, you need a Recursive Function which is a function that calls itself.

Now, back to your code. You don't need to create two functions to check and uncheck the nodes, nor using foreach for each node, child node, and child node of a child node...etc. Please try the following:

private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (e.Action == TreeViewAction.Unknown) { return; }

    foreach (TreeNode tn in GetNodes(e.Node))
        tn.Checked = e.Node.Checked;
}

private static IEnumerable<TreeNode> GetNodes(TreeNode parentNode)
{
    foreach (TreeNode tn in parentNode.Nodes)
    {
        yield return tn;

        foreach (TreeNode child in GetNodes(tn))
        {
            yield return child;
        }
    }
}

This way, you can use this iterator to do other things to your nodes not only to check/uncheck them.

Edit

You can see this strange behaviour in the seconds 7, 10, 15.

I got your point now.

That behavior occurs when you mouse click too fast on a node so you are actually doing mouse click, mouse double click sequence. The tree view control by default does not toggle the check state of the nodes through the mouse double click unless you tell it to do so. How? Already answered by PhilP in this question.

  • Create a new class that inherits the tree view control and override the WndProc event as follow:
class TreeViewEx : TreeView
{

    public TreeViewEx()
    { }

    #region This extra to reduce the flickering

    private const int TVM_SETEXTENDEDSTYLE = 0x1100 + 44;
    private const int TVM_GETEXTENDEDSTYLE = 0x1100 + 45;
    private const int TVS_EX_DOUBLEBUFFER = 0x4;

    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

    protected override void OnHandleCreated(EventArgs e)
    {
        SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
        base.OnHandleCreated(e);
    }

    #endregion

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x203 && CheckBoxes)
        {
            int x = m.LParam.ToInt32() & 0xffff;
            int y = (m.LParam.ToInt32() >> 16) & 0xffff;
            TreeViewHitTestInfo hitTestInfo = HitTest(x, y);

            if (hitTestInfo.Node != null && hitTestInfo.Location == TreeViewHitTestLocations.StateImage)
            {
                OnBeforeCheck(new TreeViewCancelEventArgs(hitTestInfo.Node, false, TreeViewAction.ByMouse));
                hitTestInfo.Node.Checked = !hitTestInfo.Node.Checked;
                OnAfterCheck(new TreeViewEventArgs(hitTestInfo.Node, TreeViewAction.ByMouse));
                m.Result = IntPtr.Zero;
                return;
            }
        }

        base.WndProc(ref m);
    }
}
  • In the designer of the form which contains your TreeView, change the type of the TreeView to the extended one that we just created.

  • Use the same code to toggle the check state.

  • Rebuild your project.

That's it all.

Here is a quick demo. I'm mouse clicking and double clicking like crazy. However, it works as it should. Hopefully.

Tree View Demo


Related


? CheckBox not work properly when clicked on quickly multiple times



与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...