2011-07-25 67 views
1

前一段時間我寫了基於WPF的UI的簡單應用程序使用的BackgroundWorker:的BackgroundWorker停止WPF UI被刷新

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
     worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
     worker.RunWorkerAsync(); 
    } 

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     LoadTextBlock.Visibility = Visibility.Hidden; 
     if (e.Error == null) 
     { 
      foreach (TechNews news in (e.Result as List<TechNews>)) 
      { 
       NewsListBox.Items.Add(news); 
      } 
     } 
     else 
     { 
      MessageBox.Show(e.Error.Message, "Error"); 
     } 
    } 

    private void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     CNetTechNewsParser parser = new CNetTechNewsParser(); 
     parser.Parse(); 
     e.Result = parser.News; 
    } 
} 

它完美地工作呢。但是現在我再次啓動了它,發現UI停止刷新,即LoadTextBlock不會消失,並且消息不會顯示在列表框中。只有在我最小化應用程序後才刷新。

我從DoWork中刪除了所有解析功能,但得到了相同的效果。然後評論RunWorkerAsync和UI開始正常工作。所以我建議這個問題是由BackgroundWorker引起的。但我不明白它有什麼問題嗎?

感謝

+0

什麼是worker_RunWorkerCompleted功能的線程上下文?可能這個函數執行不正確的跨線程操作。嘗試使用Dispatcher.BeginInvoke進行UI更新,而不是直接控制訪問。 –

+0

@AlexFarber先前嘗試過Dispatcher.Invoke,沒有運氣。現在嘗試你的變體和瞧 - 它的工作原理!但更有趣的是,我嘗試了一次直接訪問 - 現在它也可以工作了!這是神祕的...無論如何,感謝您的答案,問題看起來被解決。 –

回答

0

我有點納悶,沒有無效的交叉線程引發錯誤(UnauthorizedAccessException),但儘管如此,你可以用它在正確的調度目標控件調用您的UI更新邏輯的擴展方法。

public static class WindowExtensions 
{ 
     public static void Dispatch(this Control control, Action action) 
     { 
      if (control.Dispatcher.CheckAccess()) 
       action(); 
      else 
       control.Dispatcher.BeginInvoke(action); 
     } 
} 

用法應該是這樣,你的情況:

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    this.Dispatch(() => 
    { 
     LoadTextBlock.Visibility = Visibility.Hidden; 
     if (e.Error == null) 
     { 
      foreach (TechNews news in (e.Result as List<TechNews>)) 
      { 
       NewsListBox.Items.Add(news); 
      } 
     } 
     else 
     { 
      MessageBox.Show(e.Error.Message, "Error"); 
     } 
    }); 
} 
+1

據我所知,RunWorkerCompleted事件處理程序由已創建BackgroundWorker的線程(即我的情況下的UI線程)運行,因此不需要跨線程操作。 [鏈接](http://msdn.microsoft.com/en-us/library/ms171728.aspx)。 「後臺線程運行您的DoWork事件處理程序,並且創建您的控件的線程運行您的ProgressChanged和RunWorkerCompleted事件處理程序」 –