wpf 线程

一、线程概述:【引用MSDN】

 通常,WPF 应用程序从两个线程开始:一个用于处理呈现,一个用于管理 UI。呈现线程有效地隐藏在后台运行,而 UI 线程则接收输入、处理事件、绘制屏幕以及运行应用程序代码。大多数应用程序都使用一个 UI 线程,但在某些情况下,最好使用多个线程。我们将在后面举例说明这一点。

UI 线程对一个名为 Dispatcher 的对象内的工作项进行排队。Dispatcher 基于优先级选择工作项,并运行每一个工作项,直到完成。每个 UI 线程都必须至少有一个 Dispatcher,并且每个 Dispatcher 都只能在一个线程中执行工作项。

要构建响应速度快、且用户友好的应用程序,诀窍是减小工作项,以最大限度地提高 Dispatcher 吞吐量。这样,工作项将永远不会因为在 Dispatcher 队列中等待处理而失效。输入与响应之间的任何可察觉的延迟都会使用户不快。

那么,WPF 应用程序应如何处理大型操作呢?如果您的代码涉及大型计算,或者需要查询某台远程服务器上的数据库,应怎么办呢?通常的办法是在单独的线程中处理大型操作,而专门让 UI 线程来负责处理 Dispatcher 队列中的工作项。当大型操作完成时,可以将结果报告给 UI 线程来显示。

一直以来,Windows 只允许创建 UI 元素的线程访问这些元素。这意味着负责某项长时间运行任务的后台线程无法更新已完成的文本框。Windows 这样做是为了确保 UI 组件的完整性。如果列表框的内容在绘制过程中被后台线程更新,那么该列表框看上去将会很奇怪。

WPF 使用一种内置互斥机制来强制执行这种协调。WPF 中的大多数类都派生自 DispatcherObjectDispatcherObject 在构造时存储对链接到当前所运行线程的 Dispatcher 的引用。实际上,DispatcherObject 与创建它的线程关联。在程序执行过程中,DispatcherObject 可以调用它的公共 VerifyAccess 方法。VerifyAccess 检查与当前线程关联的 Dispatcher,并将它与构造过程中存储的 Dispatcher 引用进行比较。如果两者不匹配,VerifyAccess 将引发异常。VerifyAccess 用于在每个属于 DispatcherObject 的方法的开头调用。

如果只有一个线程可以修改 UI,那么后台线程如何与用户交互呢?后台线程可以请求 UI 线程代表它执行操作。这是通过向 UI 线程的 Dispatcher 注册工作项来完成的。Dispatcher 类提供两个注册工作项的方法:InvokeBeginInvoke。这两个方法均调度一个委托来执行。Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。BeginInvoke 是异步的,将立即返回。

Dispatcher 按优先级对其队列中的元素进行排序。Dispatcher 队列中添加元素时可指定 10 个级别。这些优先级在 DispatcherPriority 枚举中维护。有关 DispatcherPriority 级别的详细信息可以在 Windows SDK 文档中找到

例子

private delegate void showMainDelegate();

public void showMain()

{

//要执行的代码

******

}

//调用方法

Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,new showMainDelegate(showMain));

### 回答1: 在WPF中,界面元素是通过主线程更新的,因此在使用线程更新UI时必须将操作转移到主线程。这是因为WPF是基于Windows消息循环的,任何对UI的更新必须在主线程上进行。 为了在后台线程中更新UI,可以使用Dispatcher类的Invoke或BeginInvoke方法。这两个方法允许我们将任务调度到UI线程上执行。 Invoke方法会阻塞当前线程,直到UI线程执行完毕,而BeginInvoke方法则是异步执行,不会阻塞当前线程。使用这两个方法,可以将UI更新代码包装在委托中,然后将其传递给Dispatcher对象,以便在UI线程上执行。 例如,以下是一个在后台线程中更新UI的示例: ```csharp using System; using System.Threading; using System.Windows; using System.Windows.Controls; namespace WPFThreadUpdateUI { public partial class MainWindow : Window { private Thread workerThread; private TextBox textBox; public MainWindow() { InitializeComponent(); } private void StartButton_Click(object sender, RoutedEventArgs e) { workerThread = new Thread(WorkerThreadMethod); workerThread.Start(); } private void WorkerThreadMethod() { // 后台线程中更新UI Dispatcher.Invoke(() => { textBox = new TextBox(); textBox.Text = "UI更新成功"; mainGrid.Children.Add(textBox); }); } } } ``` 在上述示例中,当点击"Start"按钮时,会创建一个后台线程并执行WorkerThreadMethod方法。在方法中,通过Dispatcher.Invoke方法将UI更新的代码封装在委托中,然后传递给Dispatcher对象以在UI线程上执行。这样就可以在后台线程中更新UI。 需要注意的是,当使用Dispatcher.Invoke或BeginInvoke方法更新UI时,一定要确保在访问UI元素之前检查调用线程UI线程之间的关系,以避免线程冲突和UI更新问题。 ### 回答2: 在WPFWindows Presentation Foundation)中,UI更新通常需要在UI线程上执行。这是因为UI元素和控件只能在其创建线程上进行更新,如果在其他线程上尝试更新UI,将会引发异常。 要在线程中更新UI,可以使用Dispatcher对象的Invoke或BeginInvoke方法。Dispatcher对象提供了对UI线程的访问,这样就可以在其他线程中向UI线程发送消息并更新UI。 示例代码如下: ```csharp // 在其他线程中更新UI private void UpdateUI() { Dispatcher.Invoke(() => { // 在UI线程上执行更新操作 // 这里可以更新UI元素或控件的属性、内容等 }); } // 启动一个新线程,并在其中更新UI private void StartUpdateThread() { Thread updateThread = new Thread(() => { // 执行其他任务... // 更新UI UpdateUI(); // 执行其他任务... }); updateThread.Start(); } ``` 在上述示例中,我们首先创建了一个新的线程`updateThread`,然后在其中调用`UpdateUI`方法,它通过`Dispatcher.Invoke()`方法将UI更新操作发送到UI线程。由于采用了Invoke方法,因此更新操作会等待UI线程完成操作后才会继续执行。 通过调用`StartUpdateThread`方法,我们可以在其他线程中启动一个新的线程来更新UI。 总结而言,通过使用Dispatcher对象的Invoke或BeginInvoke方法,可以在WPF中的其他线程中更新UI。这确保了UI更新操作的线程安全性,并避免了潜在的异常情况。 ### 回答3: 在WPF中,要更新UI,我们必须确保所有对UI元素的更改都发生在主线程上,这是因为WPF中的UI元素是线程的单元,只能由创建它的线程进行访问和修改。如果我们试图在非主线程上更新UI,可能会导致异常或者无法正确更新UI。 为了在线程之间更新UI,我们可以使用Dispatcher对象。Dispatcher是WPF应用程序中的一个功能强大的工具,它允许我们在主线程上执行操作,包括更新UI元素。 我们可以通过调用Dispatcher对象的Invoke或BeginInvoke方法来跨线程更新UI。Invoke方法是同步的,会阻塞非主线程直到UI更新完成,而BeginInvoke方法是异步的,允许非主线程继续执行而无需等待UI更新完成。 例如,我们可以使用以下代码在非主线程上更新UI元素的内容: Dispatcher.Invoke(() => { // 在主线程上更新UI的代码 label1.Content = "更新后的内容"; }); 通过这种方式,我们可以安全地在WPF中的任何线程上更新UI,而无需担心线程冲突或异常。然而,需要注意的是,频繁地在非主线程上更新UI可能会导致性能下降,因此我们应该尽量减少跨线程更新UI的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值