如何在 WinForm 组件的 UI 线程上调用?

Sté*_*écy 1 user-interface components invoke winforms

我正在编写一个 WinForm 组件,在那里我启动一个任务来进行实际处理并在继续时捕获异常。从那里我想在 UI 元素上显示异常消息。

Task myTask = Task.Factory.StartNew (() => SomeMethod(someArgs));
myTask.ContinueWith (antecedant => uiTextBox.Text = antecedant.Exception.Message,
                     TaskContinuationOptions.OnlyOnFaulted);
Run Code Online (Sandbox Code Playgroud)

现在我收到一个跨线程异常,因为该任务正在尝试从一个明显的非 UI 线程更新 UI 元素。

但是,在 Component 类中没有定义 Invoke 或 BeginInvoke。

如何从这里开始?


更新

另外,请注意 Invoke/BeginInvoke/InvokeRequired 在我的 Component 派生类中不可用,因为 Component 不提供它们。

Han*_*ant 5

您可以只向组件添加一个属性,允许客户端设置可用于调用其 BeginInvoke() 方法的表单引用。

这也可以自动完成,最好不要忘记。它需要一些相当难以理解的设计时魔法。这个不是我自己想出来的,我是从 ErrorProvider 组件中得到的。可信来源等等。将其粘贴到您的组件源代码中:

using System.Windows.Forms;
using System.ComponentModel.Design;
...
    [Browsable(false)]
    public Form ParentForm { get; set; }

    public override ISite Site {
        set {
            // Runs at design time, ensures designer initializes ParentForm
            base.Site = value;
            if (value != null) {
                IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (service != null) this.ParentForm = service.RootComponent as Form;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

当用户将组件放在表单上时,设计器会自动设置 ParentForm 属性。使用 ParentForm.BeginInvoke()。