События Aftercheck и AfterSelect в Treeview в Windows Forms - PullRequest
1 голос
/ 23 октября 2019

Я настраиваю новую форму, и у меня есть некоторые проблемы с TreeViewNodes, проверяющими и снимающими флажки потомковЛегче увидеть проблему в этом коротком клипе

Обычно он работает правильно, но иногда застревает (я думаю, что есть конфликт с выбором, но я не уверен), и методы не применяютсяправильно.

У меня есть следующие методы для проверки и снятия отметки с потомков:

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

И я попытался сделать выбор пустым:

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

Но проблемаостается. Есть идеи? Спасибо

1 Ответ

0 голосов
/ 24 октября 2019

Ответы на вопрос , который я упомянул в своем комментарии, показывают нам различные способы, как перебирать узлы древовидного представления. Для этого вам понадобится Рекурсивная функция , которая является функцией, которая вызывает себя .

Теперь вернемся к вашему коду. Вам не нужно создавать две функции для проверки и снятия отметки с узлов, а также не использовать foreach для каждого узла, дочернего узла и дочернего узла дочернего узла ... и т. Д. Пожалуйста, попробуйте следующее:

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

Таким образом, вы можете использовать этот итератор для выполнения других операций с вашими узлами, а не только для их проверки / снятия.

Редактировать

Вы можете увидеть это странное поведение в секундах 7, 10, 15.

Я получил вашу точку зрения.

Такое поведение происходит, когда выслишком быстрый щелчок мышью на узле, поэтому вы фактически делаете щелчок мышью, последовательность двойного щелчка мышьюЭлемент управления древовидного представления по умолчанию не переключает состояние проверки узлов с помощью двойного щелчка мышью, если вы не попросите его сделать это. Как? На этот вопрос уже ответили PhilP в .

  • Создайте новый класс, который наследует элемент управления древовидной структуры, и переопределите событие WndProc . следующим образом:
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);
    }
}
  • В конструкторе формы, содержащей ваше древовидное представление, измените тип древовидного представления на расширенный, который мы только что создали.

  • Используйте тот же код для переключения состояния проверки.

  • Перестройте свой проект.

Этовсе это.

Вот короткая демонстрация. Я щелкаю мышью и дважды щелкаю как сумасшедшая. Однако работает как надо. Надеюсь.

Tree View Demo

Удачи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...