vote buttons
2
1
beginner
0
intermediate
0
advanced
20-Nov-2014 05:17 UTC
Super Human
1164

1 Answers

vote buttons
2

In Desktop Applications (WPF or Winforms), any UI element created on a thread is accessible only to that thread, and is not available to other threads. This is called Thread Affinity. If an attempt is made to access the ui element from any thread, other than a thread that created it, it can leave the state of the control in an invalid state or the runtime will throw an exception. In WPF all objects which subsequently derive from DispatcherObject have threads affinity (Yes, that includes some non UI objects like ObservableCollection too). In winforms objects deriving from Control class have thread affinity. So what if some thread wants to access a UI element not created by it? As it cannot run the code which accesses the UI element, it has to marshall the code to its owner, so that the owner thread can run the code. We have a few options to simplify this task:


Using Dispatcher.Invoke / BeginInvoke (WPF) 

Action uiAction = () => txtbox.Text = "Done"; // The code we want to pass to UI thread
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, uiAction);


Using Control.Invoke / BeginInvoke (Winforms)

Action uiAction = () => txtbox.Text = "Done";
txtbox.Invoke(uiAction);


Using BackgroundWorker 

Instead of manually assigning work to another thread from UI thread, you can use BackgroundWorker class. 

var bgWorker = new BackgroundWorker { WorkerReportsProgress = true };

bgWorker.DoWork += (o, e) =>
{
    //Worker thread code. Gets called in a Non-UI thread.
};

bgWorker.ProgressChanged += (o, e) =>
{
    //Progress change gets called on the UI thread. Controls can be accessed safely
};
            
bgWorker.RunWorkerCompleted += (o, e) =>
{
    //gets called when worker thread finishes. UI thread. Controls can be accessed safely
};

bgWorker.RunWorkerAsync();


Using Task Continuations 

If we use the TaskScheduler returned from helper function TaskScheduler.FromCurrentSynchronizationContext() in the continuation task, the code will get executed in a UI thread.

Task.Factory.StartNew<string>(CodeToRunOnNonUIThread)
    .ContinueWith(ant => txtBox.Text = "Done",
    TaskScheduler.FromCurrentSynchronizationContext());
20-Nov-2014 05:20 UTC
Super Human
1164