繁体   English   中英

C#检测调用是否在同一个UI操作中

[英]C# detect if calls were in the same UI action

我的winforms应用程序中有一些很好的,有效的编辑 - 撤消功能。 它使用CommandStack类,它是两个Stack<IStateCommand> (一个用于撤销,一个用于重做)。 每个命令都有一个ExecuteUndo方法, CommandStack对象本身有一个在更改堆栈时触发的事件。

如果从其自己的撤销功能调用LogCommand方法,并且因此将其添加到重做堆栈而不是撤消堆栈, CommandStack也可以运行。 这是通过简单地将当前的ManagingThreadId添加到List<int>对象,然后在完成Undo命令后删除它来完成的(而不是使用堆栈跟踪,我相信这会慢得多,有点脏)。

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

目前唯一的问题是,其中的一些UI事件也会调用其他UI事件,这两个事件都会将IStateCommand记录到撤消历史记录中。 如果已经从同一个UI事件(Click,DragDrop,SelectedIndexChanged,TextChanged等)调用了LogCommand函数,我可以检测到C#中的任何方法,然后我可以将命令组合成一个命令(使用我的CommandList类,还继承了IStateCommand )?

我曾想过在调用undo事件时保存当前时间,然后如果记录下一个命令的时间不到x毫秒,请将它们合并到历史记录中,但这看起来有点草率。 我也考虑过搜索堆栈跟踪,但我真的不知道要查找根UI事件的内容,也不知道我是否会在一次按钮点击之间说出不同的信息,然后点击同一个按钮按钮。

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

谢谢!

排序版本

从同一UI事件(例如,MouseUp,DragDrop)调用两次相同的方法。 第二次调用此方法时,如何检查它是否已被同一UI事件调用一次?

编辑:解决方案(有点)

这有点脏,因为我没有时间完全重写这个系统。 但是我已经以这样的方式实现它,以便将来可以选择不那么脏。

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

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

可能是向命令添加本地堆栈的被调用命令的选项。

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

编辑

我不太清楚你不明白。

我只是将一个CommandList属性添加到StateCommand。 每当StateCommand调用/触发另一个StateCommand时,它应该将新的StateCommand添加到CommandList。 因此,全局CommandList会跟踪可以从UI撤消的命令,并且每个StateCommand都会跟踪它调用的StateCommands(因此这些命令不会添加到全局撤消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类中,该类也实现了引用计数来处理嵌套的用法 第一次使用启动序列, 使用语句的子句增加并减少引用计数以知道序列何时完成。 最外层的上下文处理触发了包含所有嵌套命令的事件。 在我的具体情况下,它完美地工作,我不知道它是否可以满足您的需求......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM