c#检测调用是否在相同的UI操作中

本文关键字:UI 操作 检测 调用 是否 | 更新日期: 2023-09-27 18:11:13

在我的winforms应用程序中有一些不错的,工作的编辑-撤销功能。它使用CommandStack类工作,这是两个Stack<IStateCommand>(一个用于撤销,一个用于重做)。每个命令都有一个Execute和一个Undo方法,CommandStack对象本身有一个事件,当堆栈被改变时触发。

CommandStack还计算出LogCommand方法是否从其自己的Undo函数调用,因此将其添加到重做堆栈,而不是撤消堆栈。这是通过简单地将当前的ManagingThreadId添加到List<int>对象中,然后在Undo命令完成后将其删除来完成的(与使用堆栈跟踪相反,我认为这会慢得多,而且有点脏)。

在我的应用程序中有很多不同的命令,所以这个公式是固定不变的,因为我需要几天的时间来重做所有这些IStateCommand的实现。

唯一的问题是,目前,一些UI事件也调用其他UI事件,这两个记录一个IStateCommand到撤消历史。c#中是否有任何方法可以检测LogCommand函数是否已经从相同的UI事件(单击,拖放,SelectedIndexChanged, TextChanged等)中调用,那么我可以将这些命令组合成一个命令(使用我的CommandList类,也继承IStateCommand)?

我想过在调用undo事件时保存当前时间,然后如果下一个命令在不到x毫秒后被记录,则将它们合并到历史记录中,但这似乎有点草率。我也考虑过搜索堆栈跟踪,但我真的不知道要寻找什么来找到根UI事件,我也不知道我是否会告诉一个按钮单击之间的不同,然后在同一按钮上单击不同的按钮。

知道所有这些命令都是从事件处理程序(主要是从自定义用户控件的事件)的UI线程调用的可能也很有帮助。我的应用程序中唯一使用另一个线程的部分在大多数UI事件之后运行,在undo历史记录之后。

谢谢!

<

排序版本/strong>

相同的方法被从相同的UI事件(例如,鼠标向上,拖放)调用两次。第二次调用这个方法时,我如何检查它是否已经被同一个UI事件调用过一次?

编辑:解决方案(sort of)

这是一个有点脏的,因为我没有时间完全重写这个系统。然而,我已经以这样一种方式实现了它,即在将来提供了不那么脏的选项。

解决方案是基于Erno对他的答案的一个评论(所以我将把他的答案标记为接受),他建议在其中添加一个参数。我在CommandStackLogCommand(IStackCommand, string)中为LogCommand(IStackCommand)方法添加了另一个重载。该字符串是actionId,为每个命令存储,如果该字符串与最后一个字符串相同,则合并命令。这提供了遍历每个事件并给出唯一ID的选项。

然而,肮脏的部分 -在我们必须显示客户端之前让它工作,actionId默认为System.Windows.Forms.Cursor.Position.ToString(),哎哟!!由于光标的位置在UI线程执行时不会改变,因此这将合并每个命令。它实际上甚至结合了TextChanged命令(只要他们不移动鼠标!)

c#检测调用是否在相同的UI操作中

这可能是一个选项,添加一个本地堆栈调用命令的命令。

当命令执行其他命令时,将该命令添加到本地堆栈中,以便在必须撤消或重做命令时可以撤消该本地堆栈中的命令。

编辑

我不太确定你有什么不明白的。

我将简单地添加一个CommandList属性到StateCommand。每次StateCommand调用/触发另一个StateCommand时,它都应该将新的StateCommand添加到CommandList中。所以全局CommandList会跟踪可以从UI中撤消的命令,每个StateCommand会跟踪它调用的StateCommand(所以这些不会添加到全局undo CommandList)

编辑2

如果您不能或不想更改为该设置,则必须将一个参数传递给将它们连接在一起的命令的执行。

您是否尝试检查方法堆栈并逐个方法进行分析?

    StackTrace st = new StackTrace();
    for ( int i=0; i<st.FrameCount; i++ )
{
    StackFrame sf = st.GetFrame(i);
    MethodBase mb = sf.GetMethod();
    // do whatever you want
}   

我不知道你到底需要什么,但我实现了一些类似的东西,也许你可以得到一些想法…

总而言之,您可以在ThreadStatic变量中存储一些信息。然后,每当您想记录命令时,检查线程静态变量以找出记录命令的上下文。如果它为空,则开始一个新的命令日志记录序列。如果不是,则在序列中。

也许你可以存储输入事件(例如Click, DragDrop,…),或者命令本身…这取决于你的需要。当初始事件回调完成时,清理静态变量以表示序列已经完成。

我成功地实现了一个类似于跟踪命令在对象模型上执行的策略。我将逻辑封装在一个IDisposable类中,该类还实现了引用计数,以处理嵌套使用。使用语句的第一个开始序列,使用语句的后续增加或减少引用计数以知道序列何时完成。最外层的上下文处理触发了一个包含所有嵌套命令的事件。在我的特殊情况下,它工作得很好,我不知道它是否可以满足您的需求。