(这个问题有一点历史,请耐心听我说)
In this https://stackoverflow.com/questions/192980/boiler-plate-code-replacement-is-there-anything-bad-about-this-code问题,我谈到了集中更新 GUI 所需的“跨线程”骗局的可能性,如下所示:
//Utility to avoid boiler-plate InvokeRequired code
//Usage: SafeInvoker.Invoke(myCtrl, () => myCtrl.Enabled = false);
public static void Invoke(Control ctrl, Action cmd)
{
if (ctrl.InvokeRequired)
ctrl.BeginInvoke(new MethodInvoker(cmd));
else
cmd();
}
上周,仔细考虑了这样一个事实:在处理事件时,这种情况总是会发生(在我的代码中),部分灵感来自达斯汀·坎贝尔 http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx的事件扩展方法,我编写了这个:
//Utility to avoid boiler-plate SafeInvoker.Invoke code
//Usage obj.EventRaised += obj_EventRaised.OnGUIThread(controlreference);
public static EventHandler OnGUIThread(this EventHandler h, Control ctrl)
{
// lambda expressions are not syntactic sugar, they are syntactic crack!
return (s, e) => SafeInvoker.Invoke(ctrl, () => h(s, e));
}
这里让我烦恼的是总是必须有一个控件在手。据我所知,只有一个 GUI 线程,因此任何控件都可以在这里执行。
我想知道如何创建一个“GUIContext”单例,并在应用程序启动时向它抛出对我的主窗体的引用,然后从我的扩展方法访问它,从而消除对 ctrl 参数的需要。
这是一个坏主意吗?如果是的话,为什么?有更好的方法吗?我知道在 Rx 中有一个 Context 的概念,但我不知道在 vanilla WinForms 中有什么等价的东西。我可以想象如果我尝试更新尚未处理的控件可能会出现问题(但在这种情况下我无论如何都搞砸了 https://stackoverflow.com/questions/246058/system-invalidoperationexception-the-object-is-currently-in-use-elsewhere-ho).