Saturday, April 23, 2011

How to use BackgroundWorker to update UI in WPF


In this article I explained BackgroundWorker functionality using simple example. In this example I am adding millions of number in background to the Listbox. During this addition UI will be responsive and user can do some other work. When update complete it will notify user about the same.

BackgroundWorker in WPF

BackgroundWorker automatically perform task in separate thread and provide a notification to UI Thread when necessary. If you have long running task in your application you should consider putting this in separate background thread so that your UI remains responsive.

Whatever work you want to perform in background you can add it into DoWork event of BackgroundWorker. It has RunWorkerCompleted event too which fires when BackgroundWorker completes its task. So you can write some code in this event to notify user about completion of BackgroundWorker thread. To Start BackgroundWorker, use RunWorkerAsync method. When you call this method it will start executing code written in DoWork event.

XAML

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.1*"/>
            <RowDefinition />
            <RowDefinition Height="0.2*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Margin="5"
                   HorizontalAlignment="Right" Text="List of Numbers:" />
        <TextBlock Grid.Row="1" Grid.Column="0" Margin="5" Height="25"
                   HorizontalAlignment="Right" Text="" Name="Status"
                   Background="Yellow" VerticalAlignment="Top"/>
        <ListBox Grid.Row="0" Grid.Column="1" Name="NumbersList"
                 Grid.RowSpan="2"/>
        <Button Grid.Row="2" Grid.ColumnSpan="2" Height="30"
                Width="125" Content="Fill ListBox"
                Name="FillListBox" Click="FillListBox_Click" />
</Grid>

Code
        BackgroundWorker workerThread;
        public BackgroundWorkerSample()
        {
            InitializeComponent();
            workerThread = new BackgroundWorker();
            workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
            workerThread.RunWorkerCompleted += new
                RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);
        }

        private void workerThread_RunWorkerCompleted(object sender,                                                              RunWorkerCompletedEventArgs e)
        {
            Status.Text = "Completed";
            FillListBox.IsEnabled = true;
        }

        private void workerThread_DoWork(object sender, DoWorkEventArgs e)
        {
            Action<int> workMethod = (i) => NumbersList.Items.Add("Number: " + i);
            for (int i = 0; i < 1000000; i++)
                NumbersList.Dispatcher.BeginInvoke(DispatcherPriority.Background, 
                workMethod, i);
        }

        private void FillListBox_Click(object sender, RoutedEventArgs e)
        {
            workerThread.RunWorkerAsync();
            FillListBox.IsEnabled = false;
            Status.Text = "Loading...";
        }







2 comments:

  1. Hi,

    Thanks for your post.

    I used this code but what happens in my case that workerThread_RunWorkerCompleted event called and label shows "Completed" while workerThread_DoWork still working and items are adding in the list.

    Please tell me the root cause.

    Regards,
    Prateek

    ReplyDelete