我已经痛苦地意识到,在事件驱动的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一样,将函数附加到对象上,无需执行所有这些额外的工作就可以进行检查,那就太棒了。可见= true类型快捷方式。
前面的回答讨论了每次只调用Invoke()的不可行性,即使这样,Invoke()语法也是低效的,而且处理起来仍然很尴尬。
有人找到什么捷径了吗?
你不应该写这样的代码:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
如果你确实有这样的代码,那么你的应用程序就不是线程安全的。这意味着您的代码已经从不同的线程调用DoGUISwitch()。现在检查它是否在另一个线程中已经太晚了。在调用DoGUISwitch之前必须调用InvokeRequire。您不应该从不同的线程访问任何方法或属性。
参考:控制。InvokeRequired财产
你可以在这里阅读以下内容:
除了InvokeRequired属性之外,还有四个方法
调用一个线程安全的控件:Invoke, BeginInvoke, EndInvoke
和CreateGraphics(如果控件的句柄已经为)
创建。
在单CPU架构中没有问题,但在多CPU架构中,你可以将部分UI线程分配给运行调用代码的处理器……如果这个处理器与UI线程运行时的处理器不同,那么当调用线程结束时,Windows将认为UI线程已经结束,并将杀死应用程序进程,即你的应用程序将正常退出。
你不应该写这样的代码:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
如果你确实有这样的代码,那么你的应用程序就不是线程安全的。这意味着您的代码已经从不同的线程调用DoGUISwitch()。现在检查它是否在另一个线程中已经太晚了。在调用DoGUISwitch之前必须调用InvokeRequire。您不应该从不同的线程访问任何方法或属性。
参考:控制。InvokeRequired财产
你可以在这里阅读以下内容:
除了InvokeRequired属性之外,还有四个方法
调用一个线程安全的控件:Invoke, BeginInvoke, EndInvoke
和CreateGraphics(如果控件的句柄已经为)
创建。
在单CPU架构中没有问题,但在多CPU架构中,你可以将部分UI线程分配给运行调用代码的处理器……如果这个处理器与UI线程运行时的处理器不同,那么当调用线程结束时,Windows将认为UI线程已经结束,并将杀死应用程序进程,即你的应用程序将正常退出。
你可以写一个扩展方法:
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if(c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
像这样使用它:
object1.InvokeIfRequired(c => { c.Visible = true; });
编辑:正如Simpzon在评论中指出的那样,你也可以将签名更改为:
public static void InvokeIfRequired<T>(this T c, Action<T> action)
where T : Control
用法:
control.InvokeIfRequired(c => c.Visible = false);
return control.InvokeIfRequired(c => {
c.Visible = value
return c.Visible;
});
代码:
using System;
using System.ComponentModel;
namespace Extensions
{
public static class SynchronizeInvokeExtensions
{
public static void InvokeIfRequired<T>(this T obj, Action<T> action)
where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new object[] { obj });
}
else
{
action(obj);
}
}
public static TOut InvokeIfRequired<TIn, TOut>(this TIn obj, Func<TIn, TOut> func)
where TIn : ISynchronizeInvoke
{
return obj.InvokeRequired
? (TOut)obj.Invoke(func, new object[] { obj })
: func(obj);
}
}
}