[英]Background worker does not work properly in WPF
我想在datagrid中顯示臨時文件,因此這是一個長期的過程,我在C#.net WPF應用程序中使用后台工作程序。
我的密碼是
private System.ComponentModel.BackgroundWorker _background = new System.ComponentModel.BackgroundWorker();
private void button1_Click(object sender, RoutedEventArgs e)
{
_background.RunWorkerAsync();
}
public MainWindow()
{
InitializeComponent();
this._background.DoWork += new DoWorkEventHandler(_background_DoWork);
this._background.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(_background_RunWorkerCompleted);
this._background.WorkerReportsProgress = true;
_background.WorkerSupportsCancellation = true;
}
void _background_DoWork(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
try
{
FileInfo[] files = new
DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles();
foreach (FileInfo fi in files)
{
if (fi != null)
{
dataGrid1.Items.Add(fi);
}
}
}
catch { }
}));
}
void _background_RunWorkerCompleted(object sen, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else if (e.Error != null)
{
MessageBox.Show("Exception Thrown");
}
}
所有代碼都在運行,但是在加載datagrid時掛起,這意味着我的UI在程序運行時沒有響應。
在上述條件下,需要什么修改才能使后台工作者順利運行?
在它旁邊,如果我想添加一個與此應用程序一起進度的ProgressBar,那我該怎么辦?
謝謝
通過使用this.Dispatcher.Invoke
,您可以有效地將工作編組回UI線程。 這沒有任何意義:執行此操作時,您正在阻止UI線程。
將工作分為兩部分:
Dispatcher.Invoke
外部完成 Dispatcher.Invoke
完成,或者(最好在RunWorkerCompleted
事件處理程序中)完成。 后台工作程序組件是完全制成的,因此您不需要使用調度程序手動調度UI工作。 例如,您可以將文件存儲在填寫DoWork
方法的字段中,並用於在RunWorkerCompleted
事件中填充數據網格:
FileInfo[] files;
void _background_DoWork(object sender, DoWorkEventArgs e)
{
files = new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles();
}
void _background_RunWorkerCompleted(object sen, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else if (e.Error != null)
{
MessageBox.Show("Exception Thrown");
}
else
{
foreach (FileInfo fi in files)
{
dataGrid1.Items.Add(fi);
}
}
}
注意:如果您使用的是C#5,則現在可以使用async/await
功能,甚至更簡單。 您需要的是這樣的:
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
try
{
var files = await Task.Run(() =>
new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles()
);
foreach (var f in files)
this.dataGrid1.Items.Add(f.Name);
}
catch (Exception e)
{
MessageBox.Show("Exception thrown!"); // do proper error handling here...
}
finally
{
button1.Enabled = true;
}
}
其余所有工作由編譯器處理。
使用DirectoryInfo.EnumerateFiles 。
這行:
this.Dispatcher.Invoke
在主線程上同步執行代碼,因此使用BackgroudWorker
不會帶來任何好處,因為DirectoryInfo.GetFiles
僅在枚舉目錄中的所有文件時才返回。
另一方面, DirectoryInfo.EnumerateFiles
是惰性的。 您可以這樣寫:
void _background_DoWork(object sender, DoWorkEventArgs e)
{
var info = new DirectoryInfo(System.IO.Path.GetTempPath());
// now enumeration happens in background
foreach (var fi in info.EnumerateFiles())
{
// main thread in used only when there is next enumeration result available
Dispatcher.Invoke((Action)(() => dataGrid1.Items.Add(fi)));
}
}
嘗試從分派器中采取以下措施:
FileInfo[] files = new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles();
它只應執行涉及UI訪問或修改的小型快速操作。 請參閱此鏈接: http : //msdn.microsoft.com/en-us/magazine/cc163328.aspx
繁重的工作可以由BackgroundWorker完成,並使用Dispatcher更新dataGrid.Items集合。
嘗試通過以下方式使用分派器:
Dispatcher.BeginInvoke()
您應該在RunWorkerComplete或ProgressChanged事件處理程序中更新UI。
嘗試這樣的事情:
public Program()
{
w = new BackgroundWorker();
w.DoWork += new DoWorkEventHandler(w_DoWork);
w.ProgressChanged += new ProgressChangedEventHandler(w_ProgressChanged);
w.RunWorkerCompleted += new RunWorkerCompletedEventHandler(w_RunWorkerCompleted);
w.WorkerReportsProgress = true;
w.WorkerSupportsCancellation = true;
w.RunWorkerAsync();
}
void w_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FileInfo[] files = e.Result as FileInfo[];
foreach (FileInfo fi in files)
{
//dataGrid1.Items.Add(fi);
}
}
void w_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
FileInfo fi = e.UserState as FileInfo;
//dataGrid1.Items.Add(fi);
}
void w_DoWork(object sender, DoWorkEventArgs e)
{
var w = sender as BackgroundWorker;
FileInfo[] files = new DirectoryInfo(
Path.GetTempPath()).GetFiles();
// Using ProgressChanged
foreach (FileInfo fi in files)
{
w.ReportProgress(0, fi);
}
// Using RunWorkerCompleted
e.Result = files;
}
此外,無需在dowork中進行try / catch,在runworkercomplete事件中,異常會自動捕獲並報告為錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.