我可以在 AfterLabelEdit 期间将节点插入到 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()< /code>/
EndUpdate()
,以及这些想法的各种组合,但它们都没有任何效果。
罪魁祸首似乎是插入。 即使我尝试插入一个全新的节点,它也会立即进入编辑模式。
那么,有什么方法可以让 TreeView
不出现这种行为吗? 如果没有,是否有一个好的解决方法?
我考虑过的一些想法:
- 设置自定义 TreeViewNodeSorter。 不过,我不想对我的数据进行两次排序。
- 设置一个标志并将删除插入步骤延迟到 AfterLabelEdit 之后的某个时间点。 它可以在 WndProc 期间完成此操作,但这感觉像是一个大杂烩,很可能会以某种方式失败。
使用
BeginInvoke()
将删除插入步骤推回消息队列,如下所示:BeginInvoke(new MethodInvoker(委托( { Parent.Nodes.RemoveAt(oldIndex); Parent.Nodes.Insert(newIndex, 节点); }));
这对我来说比 #2 更有效,但我知道这可能不是
BeginInvoke()
的预期用途,并且它可能会产生我非常有限的知识的影响消息泵无法预测。
I have a subclass of System.Windows.Forms.TreeView
that's manually "bound" to a set of hierarchical data. I want the user to be able to edit the labels of the tree, and have the changes reflected back to the data. So I set LabelEdit
to true and overrode OnAfterLabelEdit
to the tune of:
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()
re-sorts the data and returns the index into which the change node moved after sorting. I was hoping I could simply move the edited node to reflect this move.
The problem is that this causes the node to stay in edit mode! I've tried calling EndEdit()
, cloning the node before inserting it, setting LabelEdit
to false and back to true, wrapping the change in BeginUpdate()
/EndUpdate()
, and various combinations of these ideas, but none of them have any effect.
The culprit seems to be the insertion. Even if I attempt to insert a totally new node, it will go into edit mode immediately.
So, is there any way to make TreeView
not behave this way? And if not, is there a good workaround?
Some ideas I've considered:
- Set a custom TreeViewNodeSorter. Would prefer not to have to sort my data twice, though.
- Set a flag and delay the remove-insert step until some point after AfterLabelEdit. It works to do it during WndProc, but this feels like a big kludge that is likely to fail somehow.
Use
BeginInvoke()
to push the remove-insert step back onto the message queue like so:BeginInvoke(new MethodInvoker(delegate( { parent.Nodes.RemoveAt(oldIndex); parent.Nodes.Insert(newIndex, node); }));
This works and seems cleaner to me than #2, but I know this is probably not how
BeginInvoke()
was intended to be used, and that it may have repercussions that my very limited knowledge of the message pump cannot predict.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果将
TreeView
的LabelEdit
设置为false
,则新添加的节点将不会处于编辑模式。您只需处理用户想要编辑标签的情况:为
TreeView
的MouseClick
事件创建一个处理程序,您可以在其中按位置获取单击的节点。 将LabelEdit
设置为true
并调用BeginEdit()
。 在AfterLabelEdit
事件的处理程序结束时(以及在适当的点调用EndEdit(...)
后),将LabelEdit
设置为再次假
。这对我有用,而 BeginInvoke 的解决方案仅更改了最后处于编辑模式的节点。
If you set
LabelEdit
for theTreeView
tofalse
, newly added nodes will not be in edit mode.You just have to handle the case where the user wants to edit a label: Create a handler for the
MouseClick
event of theTreeView
, where you get the clicked node by location. SetLabelEdit
totrue
and callBeginEdit()
. At the end of your handler for theAfterLabelEdit
event (and after callingEndEdit(...)
at an appropriate point), setLabelEdit
tofalse
again.This works for me, whereas the solution with BeginInvoke only changed which node was in edit mode at the end.
尝试创建一个全局变量,比方说:
将其初始化为
true
,在您的
OnAfterLabelEdit
方法中在更改后将其设置为false
:然后捕获
OnBeforeLabelEdit
事件如下:我注意到在“AfterLabelEdit”被触发后,“BeforeLabelEdit”被重新触发。 这就是为什么你必须立即停止它。
try create a global variable, let's say:
initialize it to
true
,in your
OnAfterLabelEdit
method set it tofalse
after your changes:then capture the
OnBeforeLabelEdit
event like this:I noticed that just after 'AfterLabelEdit' is fired, 'BeforeLabelEdit' is refired. That's why you have to stop it right there.
如果您使用数据绑定,数据源 (SomeBoundValue) 的更新是否应该触发节点刷新? 也许您可以强制货币管理器重新填充树视图...如果您担心性能,您可以使用一种排序算法,该算法可以很好地处理几乎已经排序的数据(例如,不是快速排序 - 合并或堆排序)记住)
或者您可以完全放弃数据绑定并手动处理重新定位,因为您已经使用 RepositionChangedDataNode() 完成了一半......
If you're using databinding, shouldn't the update to the data source (SomeBoundValue) trigger a refresh of the nodes? Maybe you can force the currency manager to repopulate the tree view.... If you're worried about performance you could use one of the sorting algorithms that works well with data that's almost already sorted (e.g., NOT quicksort - merge or heapsort come to mind)
Or you could dispense with data binding entirely and manually handle the repositioning since you're already half way there with RepositionChangedDataNode()....
您可以尝试在添加新节点之前取消挂钩 OnEdit 处理程序,然后重新挂钩。 我以前见过这种行为,这就是我的处理方式。
You could try to unhook your OnEdit handler before adding the new node and re-hooking it after. I've seen that behavior before and that's how I handled it.