WPF_21_多线程

多线程编程可使WPF应用程序执行后台工作,同时保持用户界面能够进行响应。WPF支持单线程单元(Single-Thread Apartment)模型:

•元素具有线程关联性 - 创建元素的线程拥有该元素,其他线程不能直接与该元素进行交互•具有关联性的WPF对象都继承自DispatcherObject类•UI线程运行整个应用程序并拥有所有WPF对象

Dispatcher

调度程序(dispatcher) 拥有应用程序线程,并管理工作项队列。当程序运行时,调度程序接受新的工作请求,并且一次执行一个任务。

从技术上看,当在新线程中第一次实例化 DispatcherObject类的派生类时,会创建调度程序。如果创建线程相互独立,并用它们显示独立的窗口,最终将创建多个调度程序。不过,大部分都保持简单方式,坚持使用一个用户界面线程和一个调度程序。

DispatcherObject

DispatcherObject实例是绑定到调度程序线程的对象,提供了三个成员:

名称说明
Dispatcher返回管理该对象的调度程序
CheckAccess()如果代码在正确的线程上使用对象,返回true
VerifyAccess()如果代码在正确的线程上使用对象,就什么都不做,否则抛出 InvalidOperationException 异常

WPF对象为保护自身会频繁调用 VerifyAccess() 方法,从而不可能在错误的线程中长时间使用一个对象。

•Dispatcher.BeginInvoke() 方法会将代码安排为调度程序的任务•Dispatcher.Invoke() 方法将指定的代码封送到调度程序线程,并且会拖延线程直到调用程序执行你的代码

BackgroundWorker

有很多方法执行异步操作,比如创建 Thread 对象。可以创建几十个线程,但如果访问共享数据就需要使用锁定机制来避免潜在错误。另外频繁创建线程或大量创建线程会产生额外的,不必要的开销。

BackgroundWorker用于简化 Windows 窗体应用程序中与线程相关的问题。为单独线程中运行耗时的任务提供了简单的方法,它在后台使用调度程序,并使用基于事件的模型对封送问题进行抽象。可以使用两个方法创建实例:

•在代码中创建 BackgroundWorker 对象,并使用代码关联事件处理程序•可在 XAML 中声明 BackgroundWorker 对象。这种优点是可使用特性关联事件处理程序

<Window.Resources>
    <cm:BackgroundWorker x:Key="backgroundWorker"
        WorkerReportsProgress="True" WorkerSupportsCancellation="True"
        DoWork="backgroundWorker_DoWork"
        ProgressChanged="backgroundWorker_ProgressChanged"
        RunWorkerCompleted="backgroundWorker_RunWorkerCompleted"/>
</Window.Resources>

1.调用 RunWorkerAsynce() 方法时,可提供一个对象,然后会被传递到 DoWork 事件中。2.当开始执行后,从CLR线程池提取一个自由线程,然后从这个线程引发DoWork事件.此时不能访问共享数据或用户界面3.完成耗时工作就会引发 RunWorkerCompleted事件通知应用程序。这个事件在调度程序线程引发,此时可以访问共享数据和用户界面

跟踪进度

如果要实现 跟踪进度 ,首先DoWork事件处理代码需要调用 ReportProgress() 方法,并提供已经完成的百分比。每次调用 ReportProgress() 方法时,都会引发 ProgressChanged 事件,此事件是从用户界面线程引发的,所以不需要使用 Dispatcher.BeginInvoke()方法。

private void UpdateProgress()
{
    backgroundWorker.ReportProgress(p);
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // 此事件在UI线程
    progressBar.Value = e.ProgressPercentage;
}

支持取消

为请求取消,代码需要调用 CancelAsync() 方法。此时不会自动发生任何操作,相反执行任务的代码(DoWork方法)需要显示地检查取消请求,执行所有清除操作,然后返回。

private void cmdCancel_Click(object sender, RoutedEventArgs e)
{
    // 手动触发取消
    backgroundWorker.CancelAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkerEventArgs e)
{
    // 省略代码
    if (backgroundWorker.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    // 省略代码

    e.Result = result;
}

当取消操作时,仍会引发 RunWorkerCompleted 事件,此时可检查任务是否已经被取消并进行相应处理。

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
    {
        MessageBox.Show("Search cancelled.");
    }
    else if(e.Error != null)
    {
        MessageBox.Show(e.Error.Message, "An Error Occurred");
    }
    else
    {
        // 正常结束耗时任务
    }

    progressBar.Value = 0;
}

技术群:添加小编微信并备注进群

小编微信:mm1552923   

公众号:dotNet编程大全      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值