WPF 的 BackgroundWorker
来源:互联网 发布:c语言编程界面 编辑:程序博客网 时间:2024/03/28 19:24
最近在做 WPF 显示和控制网络摄像机的任务。一个重要的小问题是窗口显示与后台处理的同步问题。例如,在登录(或切换状态、播放视频等)的时候,如果这么写代码:
private void BtnLogin_Click(object sender, RoutedEventArgs e){ bool isConnected = Login(m_IP, m_Port); if (isConnected) { MessageBox.Show("登录成功!"); } else { MessageBox.Show("登录失败!"); }}
那么在登录状态返回之前,窗口将一直无法响应用户操作(如移动等)。这是因为状态显示与后台处理置于同一个线程中,这显然是不合理的。
所以,更合理的做法应该是将窗口的控制与显示,和后台数据的处理,放在两个不同的线程中异步处理。WPF 的 BackgroundWorker 可以十分简洁地实现这一点。关于 BackgroundWorker,文章 Multi-threading with the BackgroundWorker 介绍得非常好,本文基于它做一些笔录。
简单实例
假设我们要在后台统计 1~10000 之间所有能被 42 整除的数字的个数,并在每次找到一个时,实时地在前端显示出来。
首先在代码开头处引用:
using System.ComponentModel;
并在事件响应函数(如 Button_Click)的主体部分加入:
BackgroundWorker worker = new BackgroundWorker();worker.WorkerReportsProgress = true;worker.DoWork += worker_DoWork;worker.ProgressChanged += worker_ProgressChanged;worker.RunWorkerCompleted += worker_RunWorkerCompleted;worker.RunWorkerAsync(10000);
也就是对 worker 对象添加了三个事件处理函数:DoWork, ProgressChanged 和 RunWorkerCompleted。DoWork 用于后台数据处理的主要过程,并在必要时候汇报进度(ReportProgress);ProgressChanged 用于在 DoWork 汇报进度时决定做什么;RunWorkerCompleted 用于在 DoWork 结束时执行后续的处理或显示等工作。
完整代码
MainWindow.xaml:
<Window x:Class="MTTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MTTest" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <DockPanel Margin="10"> <DockPanel DockPanel.Dock="Top"> <Button Name="btnDoSynchronousCalculation" Click="btnDoSynchronousCalculation_Click" DockPanel.Dock="Left" HorizontalAlignment="Left"> Synchronous (same thread)</Button> <Button Name="btnDoAsynchronousCalculation" Click="btnDoAsynchronousCalculation_Click" DockPanel.Dock="Right" HorizontalAlignment="Right"> Asynchronous (worker thread)</Button> </DockPanel> <ProgressBar DockPanel.Dock="Bottom" Height="18" Name="pbCalculationProgress" /> <ListBox Name="lbResults" Margin="0,10" /> </DockPanel></Window>
MainWindow.cs:
using System;using System.Windows;using System.ComponentModel;namespace MTTest{ /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnDoSynchronousCalculation_Click(object sender, RoutedEventArgs e) { int max = 10000; pbCalculationProgress.Value = 0; lbResults.Items.Clear(); int result = 0; for (int i = 0; i < max; i++) { if (i % 42 == 0) { lbResults.Items.Add(i); result++; } System.Threading.Thread.Sleep(1); pbCalculationProgress.Value = Convert.ToInt32(((double)i / max) * 100); } MessageBox.Show("Numbers between 0 and 10000 divisible by 7: " + result); } private void btnDoAsynchronousCalculation_Click(object sender, RoutedEventArgs e) { pbCalculationProgress.Value = 0; lbResults.Items.Clear(); BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += worker_DoWork; // background computing worker.ProgressChanged += worker_ProgressChanged; // progress reporting worker.RunWorkerCompleted += worker_RunWorkerCompleted; // computation completed worker.RunWorkerAsync(10000); } void worker_DoWork(object sender, DoWorkEventArgs e) { int max = (int)e.Argument; int result = 0; for (int i = 0; i < max; i++) { int progressPercentage = Convert.ToInt32(((double)i / max) * 100); if (i % 42 == 0) { result++; (sender as BackgroundWorker).ReportProgress(progressPercentage, i); } else (sender as BackgroundWorker).ReportProgress(progressPercentage); System.Threading.Thread.Sleep(1); } e.Result = result; } void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { pbCalculationProgress.Value = e.ProgressPercentage; if (e.UserState != null) lbResults.Items.Add(e.UserState); } void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show("Numbers between 0 and 10000 divisible by 7: " + e.Result); } }}
实际应用
基于 BackgroundWorker,文章开头的问题就可以通过如下方式解决:
private void BtnLogin_Click(object sender, RoutedEventArgs e){ string param = m_IP + ":" + m_Port; BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += Login_DoWork; worker.RunWorkerCompleted += Login_RunWorkerCompleted; worker.RunWorkerAsync(param); LabelLoginState.Content = "正在连接...";private void Connect_DoWork(object sender, DoWorkEventArgs e){ string[] param = ((string)e.Argument).Split(':'); string ip = param[0]; string port = param[1]; m_IsConnected = Login(ip, port);}private void Connect_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){ if (m_IsConnected) { LblConnectSate.Content = "已连接!"; } else { LblConnectSate.Content = "连接失败!"; }}
完!
参考文献
- Multi-threading with the BackgroundWorker.
0 0
- WPF 的 BackgroundWorker
- WPF BackgroundWorker线程与进度的处理
- WPF BackgroundWorker vs. Dispatcher
- WPF Multithreading with BackgroundWorker
- WPF--自定义控件的动态添加以及BackgroundWorker的使用
- 在WPF 中使用 BackgroundWorker
- BackgroundWorker改变WPF进度条值
- 进度条(BackgroundWorker后台线程处理)--WPF应用
- WPF 利用BackgroundWorker 动态加载UI
- BackgroundWorker的替代者!
- BackgroundWorker的替代者!
- backgroundWorker的使用。
- BackgroundWorker的使用
- BackgroundWorker的替代者!
- BackgroundWorker的测试
- backgroundWorker的使用
- 关于 BackgroundWorker 的描述
- BackGroundWorker控件的使用
- Android源码解析之(十三)-->apk安装流程
- 机器学习课堂笔记(十二)
- 数据结构之物流信息的归并排序(非递归实现)
- 教你如何使用okhttp缓存
- VS2010/MFC编程入门之二十六(常用控件:滚动条控件Scroll Bar)
- WPF 的 BackgroundWorker
- 学习心得-------计算机网络基础(1)
- CV_CAST_8U(val);的意义!
- AFNetworking 返回错误unsupported media type (415) 解决方案
- 关于Java Serial Version UID的一些说明
- 决策树分类算法之ID3
- 多进程并发编程----基于高级的动态创建进程池的模型
- 会用到的android 开发 第三方
- Python中OS模块