Friday, March 11, 2011

WPF - Custom Progress Bar in WPF

In this article, I am going to talk about customizing a ProgressBar control in pure XAML and tracking its actions in the code-behind.

Let see How to create a Custom ProgressBar.

Step 1
Create a WPF Application.

Step 2
First we need to place a regular ProgressBar control on your window.it is look like this



<Grid>
        
        <ProgressBar x:Name="PBar" Margin="48,125,45,144"/>
        
 </Grid>

Step 3
Then we need to build a custom ControlTemplate that will be assigned to the existing
ProgresBar control.Create a Style in Window.Resource element,it is look like this


<Window.Resources>

        <Style x:Key="ProgressBarStyle" TargetType="ProgressBar">
            
            <Setter Property="Template">
                
                <Setter.Value>
                    <ControlTemplate TargetType="ProgressBar">
                        <Border BorderBrush="#BBC6C4" BorderThickness="1" CornerRadius="5" Padding="1">
                            <Grid x:Name="PART_Track" >
                                <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" RadiusX="5" RadiusY="5">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FF1D5666" Offset="1"/>
                                            <GradientStop Color="#FF09B6FF"/>
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
                
            </Setter>
            
        </Style>

    </Window.Resources>

Step 4
Now define the style resources in Progress bar control,it is look like this

<ProgressBar x:Name="PBar" Margin="48,125,45,144" Style="{StaticResource ProgressBarStyle}"/>

















Click on Image for Better View

Step 5
In Code Behind,Import the following Namespace,it is look like this

using System.ComponentModel;
using System.Threading;

Step 6
Create a object of BackgroundWorker Class in MainWindow Class,it is look like this

#region Declaration

        // Create a Object of BackgroundWorker Class
        private BackgroundWorker WorkerThread = new BackgroundWorker();

        #endregion

BackgroundWorker Class
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause
your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished.

Step 7
Initialize Background Worker,it is look like this
 /// <summary>
        /// Initialize Background Worker
        /// </summary>
        private void InitializeBackgroundWorker()
        {
            try
            {
                WorkerThread.WorkerReportsProgress = true;
                WorkerThread.DoWork += new DoWorkEventHandler(WorkerThread_DoWork);
                WorkerThread.ProgressChanged += new ProgressChangedEventHandler(WorkerThread_ProgressChanged);
                WorkerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerThread_RunWorkerCompleted);

                WorkerThread.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);  
            }
        }

To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.

 void WorkerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                PBar.Value = PBar.Maximum;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);   
            }
        }

        void WorkerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                PBar.Value = e.ProgressPercentage;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void WorkerThread_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {

                for (int i = 0; i < 100; i++)
                {
                    Thread.Sleep(30);


                    WorkerThread.ReportProgress(i);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


Step 8
Call InitializeBackgroundWorker method in MainWindow Constructor,it is look like this

 public MainWindow()
        {
            InitializeComponent();

            InitializeBackgroundWorker();
        }


Run the project.
Output
















Full Code

1. XAML
<Window x:Class="WpfCustomProgressBar.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.Resources>

        <Style x:Key="ProgressBarStyle" TargetType="ProgressBar">
            
            <Setter Property="Template">
                
                <Setter.Value>
                    <ControlTemplate TargetType="ProgressBar">
                        <Border BorderBrush="#BBC6C4" BorderThickness="1" CornerRadius="5" Padding="1">
                            <Grid x:Name="PART_Track" >
                                <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" RadiusX="5" RadiusY="5">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FF1D5666" Offset="1"/>
                                            <GradientStop Color="#FF09B6FF"/>
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
                
            </Setter>
            
        </Style>

    </Window.Resources> 
    
    <Grid>
        
        <ProgressBar x:Name="PBar" Margin="48,125,45,144" Style="{StaticResource ProgressBarStyle}"/>
        
    </Grid>
</Window>

2. Code Behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;

namespace WpfCustomProgressBar
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Declaration

        // Create a Object of BackgroundWorker Class
        private BackgroundWorker WorkerThread = new BackgroundWorker();

        #endregion

        public MainWindow()
        {
            InitializeComponent();

            InitializeBackgroundWorker();
        }

        #region Initialize Background Worker

        /// <summary>
        /// Initialize Background Worker
        /// </summary>
        private void InitializeBackgroundWorker()
        {
            try
            {
                WorkerThread.WorkerReportsProgress = true;
                WorkerThread.DoWork += new DoWorkEventHandler(WorkerThread_DoWork);
                WorkerThread.ProgressChanged += new ProgressChangedEventHandler(WorkerThread_ProgressChanged);
                WorkerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerThread_RunWorkerCompleted);

                WorkerThread.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);  
            }
        }

        void WorkerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                PBar.Value = PBar.Maximum;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);   
            }
        }

        void WorkerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                PBar.Value = e.ProgressPercentage;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void WorkerThread_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {

                for (int i = 0; i < 100; i++)
                {
                    Thread.Sleep(30);


                    WorkerThread.ReportProgress(i);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion
    }
}

Download
Download Source Code

15 comments:

  1. Hi. Thank you to write about WPF! I'm starting to learn it alone and your post was very. I was trying to understand how to make a custom progress bar and this post helped me a lot of. You had distributed the source too, that make it more easy to understand.
    Thank you, continue with your work and helping another people with what you know!
    (sorry my English, i'm Brazilian).
    I saved your blog on my favorites! I will return always that i can. Thanks, again.

    ReplyDelete
  2. Hi, i wanted to say that this is a very good tutorial and i also wanted to ask you why do you name the first border "PART_Track" and the second "PART_Indicator"? i tried to change the name but it fails,, is there an explanation for that naming ? thank you

    ReplyDelete
  3. The office.live.com download service is not avalilable.

    Can you share the source code thu another service, please?

    ReplyDelete