2011-04-13 37 views
4

我在C#/ WPF/.NET 4.0中遇到了跨線程操作問題。在工作線程中創建對象並綁定到它們

情況:

我當用戶點擊一個按鈕來創建一個對象樹,然後綁定到樹。因爲創建需要很長時間(子對象被遞歸實例化),所以我使用了Thread/BackgroundWorker/Task來防止UI凍結。

問題:

我得到一個XamlParserException(必須在同一個線程中的DependencyObject創建DependencySource)綁定到對象樹時。

我明白這個問題,但怎麼解決?我無法在UI線程上創建對象樹,因爲這會凍結UI。但是我也無法在另一個線程上創建對象樹,因爲那樣我就無法綁定到它。

有沒有辦法'編組'對象到UI線程?

事件處理程序代碼(上UI線程執行)

private void OnDiff(object sender, RoutedEventArgs e) 
    { 

     string path1 = this.Path1.Text; 
     string path2 = this.Path2.Text; 

     // Some simple UI updates. 
     this.ProgressWindow.SetText(string.Format(
      "Comparing {0} with {1}...", 
      path1, path2)); 

     this.IsEnabled = false; 
     this.ProgressWindow.Show(); 
     this.ProgressWindow.Focus(); 

     // The object tree to be created. 
     Comparison comparison = null; 

     Task.Factory.StartNew(() => 
     { 

      // May take a few seconds... 
      comparison = new Comparison(path1, path2); 

     }).ContinueWith(x => 
     { 


      // Again some simple UI updates. 
      this.ProgressWindow.SetText("Updating user interface..."); 
      this.DiffView.Items.Clear(); 
      this.Output.Items.Clear(); 

      foreach (Comparison diffItem in comparison.Items) 
      { 
       this.DiffView.Items.Add(diffItem); 

       this.AddOutput(diffItem); 
      } 

      this.Output.Visibility = Visibility.Visible; 

      this.IsEnabled = true; 
      this.ProgressWindow.Hide(); 

     }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 

    } 

實施例結合

  <DataGrid.Columns> 
       <DataGridTemplateColumn CellTemplate="{StaticResource DataGridIconCellTemplate}"/> 
       <DataGridTextColumn Header="Status" Binding="{Binding Path=ItemStatus}"/> 
       <DataGridTextColumn Header="Type" Binding="{Binding Path=ItemType}"/> 
       <DataGridTextColumn Header="Path" Binding="{Binding Path=RelativePath}" 
            Width="*"/> 
      </DataGrid.Columns> 

問候, 多米尼克

+0

這將有助於如果你能告訴你的一些代碼。 – 2011-04-13 13:01:12

+0

我通過編輯操作爲問題添加了一些代碼片段。 – Korexio 2011-04-13 13:30:47

+1

你不應該在你的標題中加入'[Solved]'或者在你的問題中發佈解決方案。您將不得不等待24小時,但您應該在自己的答案中發佈解決方案,然後您可以接受(延遲後再次)。這然後向系統和其他用戶指出問題已經解決。 – ChrisF 2011-04-13 13:57:12

回答

3

您可以創建工作線程上的圖標,但你需要使用它的UI線程上之前凍結它:

  var icon = Imaging.CreateBitmapSourceFromHIcon(
       sysicon.Handle, 
       System.Windows.Int32Rect.Empty, 
       System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 
      icon.Freeze(); 
      Dispatcher.Invoke(new Action(() => this.Icon = icon)); 
+0

謝謝!這是完美的解決方案! – Korexio 2011-04-14 06:19:11

0

有您使用的Dispatcher.Invoke方法之前?我的理解是你可以在一個單獨的線程(例如Task)上執行一個長時間運行的進程,並使用Dispatcher來使用委託來更新UI線程上的控件。

private void DoWork() 
{ 
    // Executed on a separate thread via Thread/BackgroundWorker/Task 

    // Dispatcher.Invoke executes the delegate on the UI thread 
    Dispatcher.Invoke(new System.Action(() => SetDatesource(myDatasource))); 
} 
相關問題