如何在 WinForm 组件的 UI 线程上调用?
Posted
技术标签:
【中文标题】如何在 WinForm 组件的 UI 线程上调用?【英文标题】:How to invoke on the UI thread of a WinForm Component? 【发布时间】:2011-04-30 09:59:09 【问题描述】:我正在编写一个 WinForm 组件,在该组件中我启动一个任务来进行实际处理并在继续时捕获异常。从那里我想在 UI 元素上显示异常消息。
Task myTask = Task.Factory.StartNew (() => SomeMethod(someArgs));
myTask.ContinueWith (antecedant => uiTextBox.Text = antecedant.Exception.Message,
TaskContinuationOptions.OnlyOnFaulted);
现在我得到一个跨线程异常,因为该任务正在尝试从一个显然是非 UI 线程的 UI 元素。
但是,Component 类中没有定义 Invoke 或 BeginInvoke。
如何从这里开始?
更新
另外,请注意 Invoke/BeginInvoke/InvokeRequired 在我的 Component 派生类中不可用,因为 Component 不提供它们。
【问题讨论】:
【参考方案1】:你可以给你的组件添加一个属性,允许客户端设置一个表单引用,你可以使用它来调用它的 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;
当用户将您的组件放在表单上时,设计器会自动设置 ParentForm 属性。使用 ParentForm.BeginInvoke()。
【讨论】:
非常聪明的解决方案。 我观察到这段代码是在运行时调用的,并且在设计时拖放时会执行预期的操作。运行时:service.RootComponent as Form;返回空值。【参考方案2】:您可以使用委托来执行此操作。
delegate void UpdateStatusDelegate (string value);
void UpdateStatus(string value)
if (InvokeRequired)
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new object[]value);
return;
// Must be on the UI thread if we've got this far
statusIndicator.Text = value;
【讨论】:
那么,创建一个委托并调用它会使用 UI 线程吗? 应该做,没有测试过这段代码,但这是我在标准winforms中的做法 很遗憾,这不起作用,因为 InvokeRequired 方法在组件中不可用。 您通常不需要创建委托;请改用Action<T>
。
你能在组件上创建一个事件,然后从更远的地方订阅它吗?以上是关于如何在 WinForm 组件的 UI 线程上调用?的主要内容,如果未能解决你的问题,请参考以下文章