Могу ли я вставить узлы в TreeView во время AfterLabelEdit без начала их редактирования? - PullRequest
5 голосов
/ 21 марта 2009

У меня есть подкласс System.Windows.Forms.TreeView, который вручную "привязан" к набору иерархических данных. Я хочу, чтобы пользователь мог редактировать метки дерева и отражать изменения обратно в данные. Поэтому я установил LabelEdit на true и переопределил OnAfterLabelEdit на мелодию:

protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
{
    base.OnAfterLabelEdit(e);

    TreeNode node = e.Node;

    if (PassesSomeValidation(e.Label))
    {
        MyDataNode dataNode = node.Tag as MyDataNode;
        dataNode.SomeBoundValue = e.Label;

        int oldIndex = node.Index;
        int newIndex = RepositionChangedDataNode(dataNode);

        TreeNode parent = node.Parent;
        parent.Nodes.RemoveAt(oldIndex);
        parent.Nodes.Insert(newIndex, node);
    }
    else
    {
        e.CancelEdit = true;
    }
}

RepositionChangedDataNode() пересортирует данные и возвращает индекс, в который переместился узел изменения после сортировки. Я надеялся, что смогу просто переместить отредактированный узел, чтобы отразить это движение.

Проблема в том, что это заставляет узел оставаться в режиме редактирования ! Я пытался вызвать EndEdit(), клонировать узел перед тем, как вставить его, установить LabelEdit в false и вернуть в true, обернуть изменения в BeginUpdate() / EndUpdate() и различные комбинации этих идей, но ни одна из них иметь какой-либо эффект.

Кажется, виновником является вставка. Даже если я попытаюсь вставить полностью новый узел, он немедленно перейдет в режим редактирования.

Итак, есть ли способ заставить TreeView не вести себя таким образом? А если нет, то есть ли хороший обходной путь?

Некоторые идеи, которые я рассмотрел:

  1. Установить пользовательский TreeViewNodeSorter. Я бы предпочел не сортировать мои данные дважды.
  2. Установите флаг и задерживайте шаг удаления-вставки до некоторой точки после AfterLabelEdit. Это работает, чтобы сделать это во время WndProc, но это похоже на большой клудж, который может каким-то образом потерпеть неудачу.
  3. Используйте BeginInvoke(), чтобы перенести шаг удаления-вставки обратно в очередь сообщений следующим образом:

    BeginInvoke(new MethodInvoker(delegate(
    {
        parent.Nodes.RemoveAt(oldIndex);
        parent.Nodes.Insert(newIndex, node);
    }));
    

    Это работает и кажется мне чище, чем # 2, но я знаю, что, вероятно, это не то, как BeginInvoke() предназначалось для использования, и что это может иметь последствия, которые не могут предсказать мои очень ограниченные знания о насосе сообщений.

Ответы [ 4 ]

3 голосов
/ 03 сентября 2010

Если вы установите LabelEdit для TreeView на false, новые добавленные узлы не будут в режиме редактирования.

Вам просто нужно обработать случай, когда пользователь хочет отредактировать метку: создайте обработчик для события MouseClick в TreeView, где вы получите выбранный узел по местоположению. Установите LabelEdit на true и позвоните BeginEdit(). В конце вашего обработчика для события AfterLabelEdit (и после вызова EndEdit(...) в соответствующей точке) снова установите LabelEdit на false.

Это работает для меня, тогда как решение с BeginInvoke только изменило, какой узел находился в режиме редактирования в конце.

1 голос
/ 01 сентября 2009

попробуйте создать глобальную переменную, скажем:

private bool _allowEdit;

инициализировать его как true,

в вашем методе OnAfterLabelEdit установите его на false после ваших изменений:

... int oldIndex = node.Index;
    int newIndex = RepositionChangedDataNode(dataNode);

    TreeNode parent = node.Parent;
    parent.Nodes.RemoveAt(oldIndex);
    parent.Nodes.Insert(newIndex, node);
    **_allowEdit = false;**
}
else ...

затем запишите событие OnBeforeLabelEdit следующим образом:

    protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
    {
        base.OnBeforeLabelEdit(e);
        e.CancelEdit = !_allowEdit;
        _allowEdit = true;
    }

Я заметил, что сразу после того, как 'AfterLabelEdit' запущен, 'BeforeLabelEdit' обновляется. Вот почему вы должны остановить это прямо там.

0 голосов
/ 20 октября 2009

Вы можете попытаться отсоединить ваш обработчик OnEdit перед добавлением нового узла и повторным подключением его после. Я видел такое поведение раньше, и вот как я справился с этим.

0 голосов
/ 21 марта 2009

Если вы используете привязку данных, не должно ли обновление источника данных (SomeBoundValue) инициировать обновление узлов? Возможно, вы можете заставить диспетчер валют заново заполнить древовидное представление .... Если вы беспокоитесь о производительности, вы можете использовать один из алгоритмов сортировки, который хорошо работает с почти уже отсортированными данными (например, НЕ быстрая сортировка - слияние или heapsort на ум)

Или вы можете полностью отказаться от привязки данных и вручную обработать репозицию, поскольку вы уже на полпути с RepositionChangedDataNode () ....

...