我痛苦地意识到,人们需要在事件驱动的GUI代码中编写以下代码模式的频率有多高,其中
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
变成:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
在C#中,这是一个很难记住和输入的模式。有没有人想出某种快捷方式或构造来在一定程度上自动化这一点?如果有一种方法可以将一个函数附加到对象上,而不必经历所有这些额外的工作,比如object1.InvokeIfNecessary.visible = true
类型快捷方式,那就太酷了。
以前的answers已经讨论过每次只调用Invoke()是不切实际的,即使这样,Invoke()语法也是低效的,而且 * 仍然 * 难以处理。
有人想出什么捷径了吗?
9条答案
按热度按时间vlurs2pr1#
Lee的方法可以进一步简化
可以这样叫
不需要将控件作为参数传递给委托。C#会自动创建一个closure。
如果必须返回值,可以使用以下实现:
根据其他几张海报,
Control
可以概括为ISynchronizeInvoke
:DonBoitnott指出,与
Control
不同,ISynchronizeInvoke
接口需要Invoke
方法的对象数组作为action
的参数列表。Mike de Klerk建议的编辑(插入点参见第一个代码片段中的注解):
请参阅ToolmakerSteve和nawfal下面的评论,了解对该建议的关注。
r8uurelv2#
你可以写一个扩展方法:
并像这样使用它:
编辑:正如Simpzon在评论中指出的,你也可以把签名改为:
ghhkc1vu3#
这是我在所有代码中使用的表单。
我是基于博客条目here,我从未遇到过这种方法失败的情况,所以我认为没有理由通过检查
InvokeRequired
属性来使代码复杂化。希望这个有用。
xqk2d5yq4#
创建一个ThreadSafeInvoke.snippet文件,然后您只需选择update语句,右键单击并选择“Surround With...”或Ctrl-K+S:
qyyhg6bp5#
以下是李、奥利弗和斯蒂芬的答案的改进/合并版本。
该模板允许灵活的、无强制转换的代码,可读性更强,而专用的委托提供了效率。
wmvff8tz6#
用法:
代码:
bq9c1y667#
我宁愿使用方法Delegate的单个示例,而不是每次都创建一个新示例。在我的例子中,我曾经显示Backroundworker从SQL示例复制和转换大量数据的进度和(信息/错误)消息。每隔一段时间,在大约70000次进度和消息调用后,我的窗体停止工作并显示新消息。当我开始使用单个全局示例Delegate时,这种情况并没有发生。
gupuwyp28#
我有点喜欢做一点不同的,我喜欢叫“我自己”,如果需要一个动作,
这是一个方便的模式,IsFormClosing是一个字段,当我关闭我的表单时,我将其设置为True,因为可能有一些后台线程仍在运行...
pdtvr36n9#
您永远不应该编写如下所示的代码:
如果你的代码看起来像这样,那么你的应用程序不是线程安全的。这意味着你的代码已经从另一个线程调用了DoGUISwitch()。现在检查它是否在另一个线程中已经太晚了。必须在你调用DoGUISwitch之前调用InvokeRequire。你不应该从另一个线程访问任何方法或属性。
参考:Control.InvokeRequired Property,您可以从中读取以下内容:
除了InvokeRequired属性之外,控件上还有四个方法可以线程安全地调用:Invoke、BeginInvoke、EndInvoke和CreateGraphics(如果已创建控件的句柄)。
在单CPU架构中没有问题,但在多CPU架构中,您可以将部分UI线程分配给运行调用代码的处理器...如果该处理器与运行UI线程的处理器不同,则当调用线程结束时,Windows将认为UI线程已经结束,并将终止应用程序进程,即您的应用程序将无错误地退出。