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

And*_*att 5 c# treeview .net-2.0 winforms

我有一个子类,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

RepositionChangedDataNode()重新排序数据并返回更改节点在排序后移动到的索引.我希望我可以简单地移动已编辑的节点以反映此移动.

问题是这会导致节点保持编辑模式!我试过调用EndEdit(),在插入节点之前克隆节点,设置LabelEdit为false并返回true,将更改包含在BeginUpdate()/中EndUpdate(),以及这些想法的各种组合,但它们都没有任何效果.

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

那么,有没有办法让TreeView这种方式表现得不那么好?如果没有,是否有一个很好的解决方法?

我考虑过的一些想法:

  1. 设置自定义TreeViewNodeSorter.但是,我不想两次排序我的数据.
  2. 设置一个标志并将删除插入步骤延迟到AfterLabelEdit之后的某个点.它可以在WndProc期间完成它,但这感觉就像一个可能以某种方式失败的大型kludge.
  3. 使用BeginInvoke()推移除嵌件的步骤返回到像这样的消息队列:

    BeginInvoke(new MethodInvoker(delegate(
    {
        parent.Nodes.RemoveAt(oldIndex);
        parent.Nodes.Insert(newIndex, node);
    }));
    
    Run Code Online (Sandbox Code Playgroud)

    对我而言,这比#2更有效,但我知道这可能不是BeginInvoke()打算如何使用,并且可能会产生影响,因为我对消息泵的知识非常有限,无法预测.

Arn*_*hea 0

如果您使用数据绑定,数据源 (SomeBoundValue) 的更新是否应该触发节点刷新?也许您可以强制货币管理器重新填充树视图...如果您担心性能,您可以使用一种排序算法,该算法可以很好地处理几乎已经排序的数据(例如,不是快速排序 - 合并或堆排序)去提醒)

或者您可以完全放弃数据绑定并手动处理重新定位,因为您已经使用 RepositionChangedDataNode() 完成了一半......