Update UI in worker thread

Key points

  • While you are still on the UI thread, capture Windows Forms’ SynchronisationContext there, and store a reference to it in a variable (originalContext) for later use. You must query SynchronizationContext.Current at this point; if you queried it inside the code passed to ThreadPool.QueueUserWorkItem, you might get whatever synchronization context is associated with the thread pool’s worker thread. Once you have stored a reference to Windows Forms’ context, you can use it anywhere and at any time to “send” code to the UI thread.
  • Whenever you need to manipulate a UI element (but are not, or might not be, on the UI thread anymore), access Windows Forms’ synchronization context via originalContext, and hand off the code that will manipulate the UI to either Send or Post.
  • If you’re programming against .NET 4.5 or later, you can make your life much easier by converting your code that explicitly uses SynchronizationContext, ThreadPool.QueueUserWorkItem over to the new async / await keywords and the Task Parallel Library (TPL), i.e. the API surrounding the Task and Task<TResult> classes. These will, to a very high degree, take care of capturing the UI thread’s synchronization context, starting an asynchronous operation, then getting back onto the UI thread so you can process the operation’s result.

you cannot update UI elements on worker thread

				
					<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button x:Name="button" Content="something" HorizontalAlignment="Left" Height="20" Margin="367,71,0,0" VerticalAlignment="Top" Width="79" Click="ChangeLabelClick" />
        <Label x:Name="label" Content="button" HorizontalAlignment="Left" Height="25" Margin="119,121,0,0" VerticalAlignment="Top" Width="111" Foreground="#FFFF0606" />
    </Grid>
</Window>  
				
			

solution to update ui element on worker thread

				
					 private void LongRunningMethod1()
        {
            Dispatcher.Invoke(new Action(() => {
                label.Content = "button pressed";
            }));
            
            Thread.Sleep(1000);
        }
				
			
  1. Continuation is back on calling thread
  2. Async Await takes care of switching back to main thread
				
					 private async Task LongRunningMethod2()
        {
            await Task.Delay(1000);
            label.Content = "button pressed";
        }
				
			
  • one more example
  • If you are still using old threadpool and synchronisationcontext then do follow as mentioned
  • Get the UI thread context initially when the application kicks off
  • Get the context in worker thread method and use send or post to update the UI elements

Leave a Comment