Using XAML Progress Bar In WPF

Long-running tasks in any application make the application or software nonresponsive. So to keep the user updated about the running task and also to keep the application responsive while executing the long-running tasks, we can use different kinds of loading bar options, such as -

  • Progress Bar
  • Ring Bar etc.

Let's discuss XAML Progress Bar in WPF Apps.

What is Progress Bar?

XAML Progress Bar represents a control that indicates that an operation is ongoing. It looks like this.

WPF

XAML Progress Bar has 2 states.

  • Determinate
  • Indeterminate

Determinate

In this state, the user will be aware of the amount of the operation which has been completed.

WPF

Indeterminate

We use this state of progress bar when not sure about the total execution time of a lengthy task. See the second-to-last picture to see its shape.

WPF
Getting started with a simple example

Open Visual Studio and make a blank WPF App.

WPF

Once you click ok, you'll see an empty application like this.

WPF

We need 4 controls to implement the Progress Ring Control in this app.
  1. Button
  2. Progress Bar
  3. 2 Text blocks

    WPF 

Button to start a lengthy task, 1 label to show time, and other to show status.

Make a grid and place these controls accordingly.

  1. <Window x:Class="WPFProgressBar.MainWindow"  
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  6.         xmlns:local="clr-namespace:WPFProgressBar"  
  7.         mc:Ignorable="d"  
  8.         Title="MainWindow" Height="350" Width="525">  
  9.     <Grid>  
  10.         <Grid.RowDefinitions>  
  11.             <RowDefinition></RowDefinition>  
  12.             <RowDefinition></RowDefinition>  
  13.             <RowDefinition></RowDefinition>  
  14.             <RowDefinition></RowDefinition>  
  15.             <RowDefinition></RowDefinition>  
  16.         </Grid.RowDefinitions>  
  17.   
  18. <Button Grid.Row="1" x:Name="btn_StartLengthyTask" Click="btn_StartLengthyTask_Click" Width="200" Height="30" >Start Lengthy Task</Button>  
  19.   
  20. <ProgressBar Grid.Row="2" x:Name="pb_LengthyTaskProgress" Margin="10,20"  Value="10" ></ProgressBar>  
  21.   
  22. <TextBlock Grid.Row="3" x:Name="lbl_CountDownTimer" HorizontalAlignment="Center" > 00:10</TextBlock>  
  23.           
  24. <TextBlock Grid.Row="4" x:Name="lbl_TaskStatus" >Status...</TextBlock>  
  25.     </Grid>  
  26. </Window>  
Now, move to the code behind for button click.

Add the following code.

  1. private void btn_StartLengthyTask_Click(object sender, RoutedEventArgs e)  
  2.         {  
  3.             lbl_TaskStatus.Text = "Starting long Task...";  
  4.   
  5.             Thread.Sleep(1000);  
  6.   
  7.             lbl_TaskStatus.Text = "In Progress...";  
  8.   
  9.             pb_LengthyTaskProgress.Value = 0;  
  10.   
  11.             Task.Run(() =>  
  12.             {  
  13.                 for (int i = 0; i < 100; i++)  
  14.                 {  
  15.                     Thread.Sleep(50);  
  16.                     this.Dispatcher.Invoke(() => //Use Dispather to Update UI Immediately  
  17.                     {  
  18.                         pb_LengthyTaskProgress.Value = i;  
  19.                         lbl_CountDownTimer.Text = i.ToString();  
  20.                     });  
  21.                 }  
  22.             });  
  23.         }  

You need to use the following namespaces to work with Tasks.

  1. using System.Threading.Tasks;   

Build the project and run it. Once you click the button, Progress Bar will appear for 5 seconds.

This is useful when you know the total time a task is going to take to complete but what if you are not sure about the time left for the task to complete? In that case, we’ll start our task on a different thread and start the progress ring immediately after that. And, once the task gets done, we’ll stop the progress ring as well. I’m going to write about this in my upcoming article. Stay tuned!

WPF

This is fine. But one major problem is left. Are we sure that the task will take a specific time? If the time for a lengthy task is defined, then it's ok to work like that. But what if this is not the case?

So for that, we need to run a separate task on button click in a background thread. We'll again use TPL ( Task parallel library ) for this.