2012-10-03 110 views
0

我想在数据网格中显示临时文件,因此这是一个长期的过程,我在我的C#.net WPF应用程序中使用后台工作。后台工作人员在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"); 
      } 

    } 

所有的代码运行,但是当数据网格是装载意味着我的UI做程序运行时没有响应它挂起。

在上述情况下需要做些什么修改才能顺利运行后台工作?

除此之外,如果我想添加一个ProgressBar,并与此应用程序一起进步,那我该怎么办?

谢谢你

回答

0

使用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))); 
    } 
} 
0

尝试采取这一行动关闭接线员:

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() 
3

使用this.Dispatcher.Invoke,您实际上编组工作回到UI线程。这没有任何意义:在执行此操作时,您正在阻止UI线程。

分成两个部分工作:

  • 慢的部分,这是检索文件,并应在Dispatcher.Invoke
  • 的UI更新外完成,必须在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; 
     } 
    } 

所有其余的cruft是由编译器照顾。

0

您应该更新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事件错误。