65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展方法使 WPF 线程安全编程更容易

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (10投票s)

2009年10月21日

CPOL

3分钟阅读

viewsIcon

38848

downloadIcon

351

提供扩展方法, 以简化线程安全的 UI 编程

引言

在编写多线程 WPF 应用程序时,您必须确保不要尝试从主线程以外的任何线程访问任何 UI 元素。 这可能导致重复且看起来杂乱的代码。 使用扩展方法,我们将研究一种简化方法,以提供线程安全的 UI 更新。

背景

Sacha Barber 在他的文章“有用的 WPF 线程处理扩展方法”中介绍了一种线程安全的 UI 更新方法。 本文扩展了他的想法,并提供了一个更简单的编码结构。

示例应用程序

当您运行示例应用程序时,您可以单击“开始”按钮。 这将启动一个计时器,该计时器每秒触发一次。 单击“停止”以停止计时器。 当“线程安全模式”复选框被选中时,蓝色框中的 UI 元素将每秒更新一次。 如果未选中“线程安全模式”复选框,则会发生异常。 当计时器未运行时,您也可以单击“从 UI 更新”按钮。 这将更新蓝色框中的控件,无论“线程安全模式”是否被选中,因为它从 UI 线程调用 UpdateControls。

Using the Code

使用 Sacha 的原始 Extension 方法,textBox1 的文本将设置如下

this.InvokeIfRequired(() =>
{
	textBox1.Text = "Hello World";
},
DispatcherPriority.Background);

使用我的扩展方法,textBox1 的文本将设置如下

textBox1.SetTextThreadSafe("Hello World");

要使用 Sacha 的扩展方法获取 textBox1 Text ,将是

string s = "";
this.InvokeIfRequired(() =>
{
	s = textBox1.Text = "Hello World";
},
DispatcherPriority.Background);

使用我的扩展方法设置 Text 将是

string s = textBox1.GetTextThreadSafe();

它是如何工作的?

我们只需为我们要获取或设置的值定义一个 Get Set 方法。 为了方便起见,我将这些方法放在与 InvokeIfRequired 方法相同的 static 类中。

一个示例 Set 方法

 public static string SetTextThreadSafe(this TextBox tb)
{
	string s = "";
	InvokeIfRequired(tb, () => { s = tb.Text; }, DispatcherPriority.Background);
	return s;
}

一个示例 Get 方法

public static void SetTextThreadSafe(this TextBox tb, string s)
{
	InvokeIfRequired(tb, () => { tb.Text = s; }, DispatcherPriority.Background);
}

扩展方法必须包含在 static 类中。 扩展方法也必须声明为 static 方法。 扩展方法的定义看起来有点奇怪,因为第一个参数是用关键字 this 定义的,后跟该方法扩展的类型,然后是要在方法中用于实例的名称。 仅以这种方式定义第一个参数。 其余的参数都正常定义。

最好尝试为具有您要使用的属性的最通用类创建这些方法。 这样可以防止您为每个控件类型创建类似的方法。 一个例子是 Visibility 属性。 这是一个 UIElement 的属性,因此为 UIElement 创建一个 Set Get 方法而不是为 RadioButtonLabel 等创建单独的方法是有意义的。

定义扩展方法后,它可由声明中定义的类型的任何实例或从该类型派生的任何类型使用。 它也可以被静态调用。

问答

使用 InvokeIfRequired 方法不是更容易吗?

如果您只需要使用它一两次,则可能就是这种情况。 如果您要多次访问多个 UI 元素,我认为我的扩展方法更容易。

我是否必须为每个 UI 元素属性编写一个扩展方法?

否则,您需要在每次访问 UI 元素的属性时使用 InvokeIfRequired 方法,那么为什么不将其包装在扩展方法中,这样您就只需要执行一次呢? 然后,您可以在任何需要它的应用程序中使用您的 WPFThreadingExtensions 类。

我没有看到我需要的属性的 Set 或 Get 扩展方法?

我在测试应用程序中提供了一些 Get Set 扩展方法的示例,因此您可以使用它们来帮助您了解如何编写自己的扩展方法。

如果我想使用不同的 DispatcherPriority,我该怎么办?

我在我的扩展方法中使用了 DispatcherPriority.Background。 您可以更改此项,创建一个将您需要的 DisplatcherPriority 作为参数的扩展方法,或使用 InvokeIfRequired 扩展方法。

历史

  • 2009年10月20日:初始版本
© . All rights reserved.