我可以在AfterLabelEdit期间将节点插入TreeView而不开始编辑它们吗?

时间:2009-03-20 21:30:21

标签: c# winforms .net-2.0 treeview

我有一个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()中,以及各种组合这些想法,但没有一个有任何影响。

罪魁祸首似乎是插入。即使我尝试插入一个完全 new 节点,它也会立即进入编辑模式。

那么,有没有办法让TreeView不这样做?如果没有,是否有一个好的解决方法?

我考虑过的一些想法:

  1. 设置自定义TreeViewNodeSorter。不过,我宁愿不要对数据进行两次排序。
  2. 设置一个标志并将删除插入步骤延迟到AfterLabelEdit之后的某个点。它可以在WndProc期间完成它,但这感觉就像一个很可能以某种方式失败的大块。
  3. 使用BeginInvoke()将删除插入步骤推回到消息队列中,如下所示:

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

    这对我来说比#2更有效,但我知道这可能不是BeginInvoke()的意图,并且可能会对我对消息泵的知识非常有限无法预测产生影响

4 个答案:

答案 0 :(得分:3)

如果您将LabelEdit的{​​{1}}设置为TreeView,则新添加的节点将不会处于编辑模式。

您只需处理用户想要编辑标签的情况:为false的{​​{1}}事件创建处理程序,您可以按位置获取单击的节点。将MouseClick设为TreeView并致电LabelEdit。在true事件的处理程序结束时(以及在适当的时间点调用BeginEdit()后),再次将AfterLabelEdit设置为EndEdit(...)

这对我有用,而使用BeginInvoke的解决方案只改变了最后一个节点处于编辑模式。

答案 1 :(得分:1)

尝试创建一个全局变量,让我们说:

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'被重新启动。这就是为什么你必须在那里停止它。

答案 2 :(得分:0)

如果您正在使用数据绑定,那么更新数据源(SomeBoundValue)是否应该触发刷新节点?也许您可以强制货币经理重新填充树视图....如果您担心性能,您可以使用一种排序算法,该算法适用于几乎已经排序的数据(例如,NOT quicksort - merge或heapsort come记住)

或者你可以完全省去数据绑定并手动处理重新定位,因为你已经在RepositionChangedDataNode()的一半......

答案 3 :(得分:0)

您可以尝试在添加新节点之前解开OnEdit处理程序并在之后重新挂钩。我以前见过这种行为,这就是我处理它的方式。