简体   繁体   English

在UI线程上调用一个方法,以及神秘的System.Windows.Forms.MethodInvoker.Invoke()

[英]Invoking a method on the UI thread, and the mysterious System.Windows.Forms.MethodInvoker.Invoke()

I'm trying to run code from worker threads by invoking it on the main UI thread; 我试图通过在主UI线程上调用代码来从工作线程运行代码; however, I don't have an instance of the main form or any controls (nor do I want one in the class where the threaded code is running). 但是,我没有主窗体或任何控件的实例(我也不想在运行线程代码的类中有一个)。

I've found things like the built-in System.Windows.Forms.MethodInvoker delegate, which has an Invoke() method. 我发现了内置的System.Windows.Forms.MethodInvoker委托,它有一个Invoke()方法。 I figured if I instantiated my MethodInvoker on the main thread and then called its Invoke() method on the worker thread, everything would work as I wanted. 我想如果我在主线程上实例化我的MethodInvoker然后在工作线程上调用它的Invoke()方法,一切都会按我的意愿工作。 However, simple debugging demonstrates that the invoked method still runs on the worker thread. 但是,简单的调试表明调用的方法仍然在工作线程上运行。

I can't find any documentation on MethodInvoker.Invoke() . 我在MethodInvoker.Invoke()上找不到任何文档。 There isn't even a "Members" link on MSDN for it, yet it exists. MSDN上甚至没有“成员”链接,但它存在。 The only thing I've found, which states what I already know, is the accepted answer in this SO post: 我发现的唯一一个陈述我已经知道的东西是这篇SO帖子中接受的答案:

Using C# MethodInvoker.Invoke() for a GUI app... is this good? 使用C#MethodInvoker.Invoke()获取GUI应用程序......这样好吗?

So, my questions are: 所以,我的问题是:

  1. How can I invoke a method on the main thread without an instance of the main form or other UI elements? 如何在没有主窗体或其他UI元素的实例的情况下在主线程上调用方法?

  2. Why isn't the MethodInvoker.Invoke() method documented anywhere? 为什么不在任何地方记录MethodInvoker.Invoke()方法? What am I missing? 我错过了什么?

Why isn't the MethodInvoker.Invoke() method documented anywhere? 为什么不在任何地方记录MethodInvoker.Invoke()方法? What am I missing? 我错过了什么?

It's documented. 记录在案。 It's generated by C# compiler for each declared System.Delegate together with BeginInvoke() / EndInvoke() . 它由C#编译器为每个声明的System.DelegateBeginInvoke() / EndInvoke() You seldom (or never) will have to call it directly because you simply can use function-style invocation: 你很少(或永远)不必直接调用它,因为你只需要使用函数式调用:

MethodInvoker func = ...
func(this, EventArgs.Empty);

Moreover please note that MethodInvoker is just a delegate not a class to dispatch calls to other threads . 此外,请注意, MethodInvoker只是一个委托,而不是一个分派调用其他线程的类 What does this mean? 这是什么意思? That if you invoke it then it will be called in the caller thread. 如果你调用它,那么它将在调用者线程中调用。

How can I invoke a method on the main thread without an instance of the main form or other UI elements? 如何在没有主窗体或其他UI元素的实例的情况下在主线程上调用方法?

Simply you can't. 简直就是你不能。 Fortunately you can access System.Windows.Forms.Application.OpenForms list. 幸运的是,您可以访问System.Windows.Forms.Application.OpenForms列表。 Pick first open form and use it to dispatch your call to UI thread. 选择第一个打开的表单并使用它将您的调用发送到UI线程。

if (Application.OpenForms.Count > 0)
    Application.OpenForms.BeginInvoke(...);
else
    // Ooops, no UI? You may invoke directly

When creating the class that will run off thread. 创建将运行线程的类时。 Create an event that can pass notification data out that the UI objects can hook to, then the UI can call invoke as necessary. 创建一个可以传递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);
             }
          }
        });
   }

meanwhile on the UI form that kicks things off: 同时在用户界面形式上取消了:

   var task = new MyBackgroundWorker();
   task.Progress += (myArgs) => {
       Invoke(()=> HandleEvent(myArgs));
   }

That's a bit rough, there are other answers on SO for best practices in calling the invocation. 这有点粗糙,SO上有其他答案可以调用调用的最佳实践。

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

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