Creating and linking objects in a workflow

I have a problem with cross-stream operations in C # / WPF / .NET 4.0.

Situation:

I need to create a tree of objects when the user clicks a button and then snaps to the tree. Since creation takes a lot of time (children are created recursively), I used Thread / BackgroundWorker / Task to prevent the user interface from freezing.

Problem:

I get a XamlParserException (I need to create a DependencySource in the same thread as DependencyObject) when binding to an object tree.

I understand the problem, but how can I fix it? I cannot create a tree of objects in the user interface thread because it freezes the user interface. But I also can not create a tree of objects in another thread, because then I can not bind to it.

Is there a way to "marshal" objects to a user interface thread?

Event handler code (executed in the user interface thread)

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()); } 

Binding example

  <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> 

Hello Dominik

+4
source share
2 answers

You can create a workflow icon, but you need to freeze it before using it in the user interface thread:

  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)); 
+3
source

Have you used Dispatcher.Invoke method before? My understanding is that you can execute a lengthy process in a separate thread (e.g. Task) and use the dispatcher to update controls in the user interface thread using a delegate.

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

Source: https://habr.com/ru/post/1347902/


All Articles