用于跨线程 Winforms 访问的通用方法






4.93/5 (19投票s)
使用泛型检查 Winforms 控件的 InvokeRequired 的便捷快捷方式

引言
在编写 WinForms 应用程序时,很可能会遇到需要从另一个线程访问 Form 控件的情况,例如从 Timer.Interval
事件中。 为此,必须检查 Control.InvokeRequired
属性,如果为 true
,则必须使用 Control.Invoke
方法的委托来完成控件访问。
一个例子如下
void UpdateLabel(Label lbl, String text)
{
if (lbl.InvokeRequired)
{ lbl.Invoke(new Action<Label, String>(UpdateLabel), new object[] { lbl, text }); }
else
{ lbl.Text = text; }
}
虽然这有效,但它需要为每种控件类型以及希望从另一个线程执行的每个操作编写单独的方法。
为了封装这种跨线程访问行为,我们转向泛型。
Using the Code
我们将使用以下泛型实用程序方法来执行所有跨线程控件操作
public static void InvokeControlAction<t>(t cont, Action<t> action) where t : Control
{
if (cont.InvokeRequired)
{ cont.Invoke(new Action<t, Action<t>>(InvokeControlAction),
new object[] { cont, action }); }
else
{ action(cont); }
}
详细说明
t
是我们希望访问的控件的类型,例如Label
cont
是我们将要操作的控件的实例。action
是一个泛型委托void
,它接受t
的实例。 通过使用泛型委托,我们可以在调用代码中定义我们想要访问的t
实例的属性/方法,而不是像以前那样在方法中假定控件类型和操作。- 最后,
t
必须继承Control
才能检查InvokeRequired
属性。
所以我们执行如下
- 如果
cont.InvokeRequired
的计算结果为true
,则使用新的泛型Action<>
委托调用cont.Invoke
,该委托符合InvokeControlAction<t>
的签名,并将cont
和action
递归地传递回去。 - 如果
cont.InvokeRequired
的计算结果为false
(要么执行了步骤 1,要么从包含cont
的同一线程调用了此方法),我们执行委托action
,传入我们的控件实例...cont
。
要在实际示例中使用此方法:在我们的时钟应用程序中,我们有一个每秒触发一次的计时器。 这是 Elapsed
事件处理程序,我们在此处使用我们的实用程序方法
void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//On tick, update the time
CrossThreadUtility.InvokeControlAction<Label>
(lblTime, lbl => lbl.Text = String.Format("The current time is: {0}",
DateTime.Now.ToString("h:mm:ss tt")));
}
在这里,我们将 Label lblTime
作为 cont
传递,对于委托 action
,我们使用 C# 3.0 的 Lambda 表达式功能以内联方式编写我们的委托,以便获得简洁的一行代码。
我们在 lblTime
上执行的操作,(在 lambda 表达式中 lbl
的上下文中)很简单
lbl.Text = String.Format("The current time is: {0}",
DateTime.Now.ToString("h:mm:ss tt"))
关注点
您可以轻松地将 Label
替换为任何 Windows Forms 控件类型...尝试这样做以使时间显示在 Form 的标题栏上,而不是 Label lblTime
CrossThreadUtility.InvokeControlAction<Form>(this, frm => frm.Text =
String.Format("The current time is: {0}", DateTime.Now.ToString("h:mm:ss tt")));
结论
我们已经创建了一个实用程序方法,用于简洁的一行跨线程控件访问,而不管控件类型或访问操作如何。
历史
- 2009 年 6 月 18 日:初始发布