我的 winforms 应用程序中有一些不错的、有效的编辑撤消功能。它使用 CommandStack
工作类,这是两个 Stack<IStateCommand>
s(一个用于撤消,一个用于重做)。每个命令都有一个 Execute
和一个 Undo
方法,以及 CommandStack
对象本身有一个事件,该事件在堆栈更改时触发。
CommandStack
如果 LogCommand 方法是从它自己的 Undo 函数调用的,并且因此将它添加到重做堆栈,而不是撤消堆栈,也可以解决。这是通过简单地添加当前的 ManagingThreadId
来完成的。到 List<int>
对象,然后在撤消命令完成后将其删除(与使用堆栈跟踪相反,我认为这会慢得多并且有点脏)。
我的应用程序中有很多不同的命令,所以这个公式有点固定,因为我需要几天时间来重做所有这些 IStateCommand
s 实现。
目前唯一的问题是,其中的一些 UI 事件也会调用其他 UI 事件,这两个事件都会记录一个 IStateCommand
。到撤消历史。在 C# 中有什么方法可以检测是否已经从同一个 UI 事件(单击、拖放、SelectedIndexChanged、TextChanged 等)调用了 LogCommand 函数,然后我可以将这些命令组合成一个命令(使用我的 CommandList
类,它也继承 IStateCommand
)?
我曾经想过调用undo事件时保存当前时间,然后如果下一条命令在x毫秒后被记录,则将它们合并到历史记录中,但这似乎有点草率。我也考虑过搜索堆栈跟踪,但我真的不知道要寻找什么来找到根 UI 事件,我也不知道我是否会区分一次按钮单击和不同的单击相同的按钮按钮。
了解所有这些命令都是从事件处理程序(主要是来自自定义用户控件的事件)的 UI 线程调用的,这可能也会有所帮助。我的应用程序中唯一使用另一个线程的部分在大多数 UI 事件之后运行,在记录撤消历史记录之后。
谢谢!
排序版本
从同一个 UI 事件(例如,MouseUp、DragDrop)调用同一个方法两次。第二次调用此方法时,如何检查它是否已被同一个 UI 事件调用过一次?
编辑:解决方案(某种程度上)
这有点脏,因为我没有时间完全重写这个系统。然而,我已经以这样一种方式实现了它,它提供了将来不那么脏的选项。
该解决方案基于 Erno 对他的回答的评论之一(因此我将他的回答标记为已接受),他建议在其中添加一个参数。我在 LogCommand(IStackCommand)
中添加了另一个重载CommandStack
中的方法类,LogCommand(IStackCommand, string)
.该字符串是为每个命令存储的 actionId,如果此字符串与上一个字符串相同,则合并命令。这提供了遍历每个事件并提供唯一 ID 的选项。
但是,肮脏的部分 - 在我们必须向客户展示之前让它工作,actionId
默认为 System.Windows.Forms.Cursor.Position.ToString()
,哎哟!!由于在 UI 线程执行时光标位置没有改变,因此这结合了每个命令。它实际上什至结合了 TextChanged 命令(只要他们不移动鼠标!)
最佳答案
将调用命令的本地堆栈添加到命令可能是一个选项。
当一个命令执行其他命令时,将命令添加到本地堆栈,以便在必须撤消或重做命令时可以撤消此本地堆栈上的命令。
编辑
我不太确定你不明白什么。
我会简单地向 StateCommand 添加一个 CommandList 属性。每次 StateCommand 调用/触发另一个 StateCommand 时,它应该将新的 StateCommand 添加到 CommandList。因此全局 CommandList 跟踪可以从 UI 撤消的命令,每个 StateCommand 跟踪它调用的 StateCommand(因此这些不会添加到全局撤消 CommandList)
编辑 2
如果您不能或不想更改该设置,则必须将参数传递给执行将它们链接在一起的命令。
关于C# 检测调用是否在同一个 UI 操作中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7752698/