使用前提
在WPF程序中缆巧,有一些比較耗時的后臺操作時,比如向遠程服務(wù)器請求數(shù)據(jù)豌拙,或者通過TCP/IP為某臺設(shè)備提供升級固件服務(wù)等等陕悬。為了防止這類操作freeze用戶界面,造成用戶體驗下降按傅,即程序假死的狀況出現(xiàn)捉超。一種常見的,更user friendly的方式是逞敷,提供一個進度條窗口,提示用戶該操作的完成進度灌侣。并提供取消操作的選項推捐。
C#中的 BackgroundWorker Class 則是執(zhí)行該任務(wù)的最佳選擇。
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, theBackgroundWorker class provides a convenient solution.
-MSDN
關(guān)于 BackgroundWorker 類
主要屬性
-
CancellationPending
- 只讀屬性侧啼,default值為false牛柒,執(zhí)行CancelAsync方法后,值為true痊乾。表明應(yīng)用程序請求了取消后臺操作皮壁。 -
IsBusy
- 如果后臺異步操作開始執(zhí)行,值為true哪审,否則為false -
WorkerReportProgress
- 如果BackgroundWorker支持后臺操作進程更新蛾魄,設(shè)置值為true,default值為false
主要事件
DoWork
ProgressChanged
-
RunWorkerCompleted
不要再DoWork事件處理程序中對UI線程中的對象進行操作,操作應(yīng)該放在ProgressChanged和RunWorkerCompleted的事件處理程序中滴须。
主要方法
-
RunWorkerAsync()
- 執(zhí)行后臺操作舌狗,激發(fā)DoWork事件 -
ReportProgress()
- 激發(fā)ProgressChanged事件 -
CancelAsync()
- 提交終止后臺操作的請求,并將CancellationPending屬性值設(shè)為true扔水。在程序其他地方要定時檢查CancellationPending屬性的值痛侍,作出相應(yīng)操作,比如
if (worker.CancellationPending)
{
e.Cancel = true;
}
示例程序
XAML
<Window x:Class="BackgroundWorkerExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="300">
<StackPanel>
<ProgressBar Name="progressBar" Height="20" Width="250" Margin="10"></ProgressBar>
<TextBox Name="textBox" Width="50" Height="20" HorizontalAlignment="Center"></TextBox>
<Button Name="btnProcess" Width="100" Click="btnProcess_Click" Margin="5">Start</Button>
<Button Name="btnCancel" Width="100" Click="btnCancel_Click" Margin="5">Cancel</Button>
</StackPanel>
</Window>
C#
namespace BackgroundWorkerExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
BackgroundWorker bgworker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
bgworker.WorkerReportsProgress = true;
bgworker.WorkerSupportsCancellation = true;
bgworker.DoWork += bgworker_DoWork;
bgworker.ProgressChanged += bgworker_ProgressChanged;
bgworker.RunWorkerCompleted += bgworker_RunWorkerCompleted;
}
void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 100; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
}
else
{
worker.ReportProgress(i);
Thread.Sleep(100);
}
}
}
void bgworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
textBox.Text = e.ProgressPercentage.ToString();
}
void bgworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar.Value = 0;
if (e.Cancelled)
{
MessageBox.Show("Background task has been canceled", "info");
}
else
{
MessageBox.Show("Background task finished", "info");
}
}
private void btnProcess_Click(object sender, RoutedEventArgs e)
{
if (!bgworker.IsBusy)
{
bgworker.RunWorkerAsync();
}
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
bgworker.CancelAsync();
}
}
}