2011-04-13 81 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))); 
} 
相关问题