Aftercheck and AfterSelect events in Treeview in Windows Forms

孤人 提交于 2020-06-26 07:13:26

问题


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


回答1:


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.


Related


◉ CheckBox not work properly when clicked on quickly multiple times




来源:https://stackoverflow.com/questions/58522970/aftercheck-and-afterselect-events-in-treeview-in-windows-forms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!