我试图通过在主UI线程上调用代码来从工作线程运行代码;但是,我没有主窗体或任何控件的实例(我也不想在运行线程代码的类中有一个)。
我找到了类似内置System.Windows.Forms.MethodInvoker
委托的内容,它有Invoke()
方法。我想如果我在主线程上实例化我的MethodInvoker
,然后在工作线程上调用它的Invoke()
方法,一切都会按照我想要的方式工作。但是,简单的调试表明调用的方法仍然在工作线程上运行。
我无法在MethodInvoker.Invoke()
找到任何文档。甚至没有一个"会员"在MSDN上链接它,但它存在。我发现的唯一一个陈述我已经知道的东西,就是这篇SO帖子中接受的答案:
Using C# MethodInvoker.Invoke() for a GUI app... is this good?
所以,我的问题是:
如何在没有主窗体或其他UI元素的实例的情况下在主线程上调用方法?
为什么不在任何地方记录MethodInvoker.Invoke()
方法?我错过了什么?
答案 0 :(得分:1)
为什么不在任何地方记录MethodInvoker.Invoke()方法?我错过了什么?
记录在案。它由C#编译器为每个声明的System.Delegate
和BeginInvoke()
/ EndInvoke()
生成。你很少(或永远)不必直接调用它,因为你只需要使用函数式调用:
MethodInvoker func = ...
func(this, EventArgs.Empty);
此外请注意,MethodInvoker
只是委托,而不是将调用分派给其他线程的类。这是什么意思?如果你调用它,那么它将在调用者线程中调用。
如何在没有主窗体或其他UI元素的实例的情况下调用主线程上的方法?
简单地说,你不能。幸运的是,您可以访问System.Windows.Forms.Application.OpenForms
列表。选择第一个打开的表单并使用它来调用UI线程。
if (Application.OpenForms.Count > 0)
Application.OpenForms.BeginInvoke(...);
else
// Ooops, no UI? You may invoke directly
答案 1 :(得分:1)
创建将运行线程的类。创建一个可以传递UI对象可以挂钩的通知数据的事件,然后UI可以根据需要调用invoke。
class MyBackgroundWorker
{
public event EventHandler<MyArgs> Progress;
public void Start()
{
Task.Factory.StartNew(() => {
while(shouldBeDoingStuff) {
... stuff to be done ...
if (Progress)
{
Progress(myArgs);
}
}
});
}
同时在用户界面形式上取消了:
var task = new MyBackgroundWorker();
task.Progress += (myArgs) => {
Invoke(()=> HandleEvent(myArgs));
}
这有点粗糙,SO上有其他答案可以调用调用的最佳做法。