DEV Community

Rupesh Ghosh
Rupesh Ghosh

Posted on • Updated on

Create a Custom Progress Bar with moving percentage in WPF

Introduction

As a dotnet developer, you may have found yourself in need of a progress bar to indicate the progress of a task. While the built in WPF progress bar is functional, it may not always fit the specific requirements of your project. In this blog post, I will show you how to create a custom progress bar with a moving percentage in WPF.

Project setup

To get started, we'll create a separate WPF user control library for our custom progress bar. This will allow us to reuse the progress bar in different projects without having to write the same code over and over again.
Here are the steps to create a WPF user control library in Visual Studio:

  1. Open Visual Studio and create a new project.
  2. In the New Project dialog box, select WPF User Control Library and click Next.
  3. Give your project a name and click Next.
  4. Select the dotnet version and click Create.

Designing the custom progress bar

To create a custom progress bar with a moving percentage in WPF, we'll need to use two converters. Converters are classes that can convert one type of value to another and are used in WPF to bind UI elements to data. In this case, we'll use two converters to bind the progress bar's width to its value, and its inverse width to its remaining value (i.e 100 - value).

Add below two converters the project:

  • ProgressBarValueToWidthConverter
internal class ProgressBarValueToWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var progressBarValue = System.Convert.ToDouble(value);

        if (progressBarValue >= 100)
        {
            return "100*";
        }

        return $"{progressBarValue}*";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • InverseProgressBarValueToWidthConverter
internal class InverseProgressBarValueToWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var progressBar = System.Convert.ToDouble(value);

        if (progressBar >= 100)
        {
            return "0*";
        }

        return $"{100.0 - progressBar}*";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Enter fullscreen mode Exit fullscreen mode

By using these two converters in combination, we can create a progress bar that dynamically moves the percentage value of the progress bar as the task progresses.

Now, Add a new UserControl name 'CustomProgressBar' to the project.

  • CustomProgressBar.xaml
<UserControl x:Class="CustomProgressbar.Progressbar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:converters="clr-namespace:CustomProgressbar.Converters"
             mc:Ignorable="d"
             x:Name="CustomProgressBarUC">

    <UserControl.Resources>
        <converters:ProgressBarValueToWidthConverter x:Key="ProgressBarValueToWidthConverter" />
        <converters:InverseProgressBarValueToWidthConverter x:Key="InverseProgressBarValueToWidthConverter" />
    </UserControl.Resources>

    <StackPanel HorizontalAlignment="Center">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{Binding ElementName=CustomProgressBarUC, Path=ProgressBarValue, Converter={StaticResource ProgressBarValueToWidthConverter}}" />
                <ColumnDefinition Width="{Binding ElementName=CustomProgressBarUC, Path=ProgressBarValue, Converter={StaticResource InverseProgressBarValueToWidthConverter}}" />
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding ElementName=CustomProgressBarUC, Path=ProgressBarValue, StringFormat={}{0:F0}%}"
                       FontSize="9px"
                       HorizontalAlignment="Right" />
        </Grid>
        <ProgressBar Minimum="0"
                     Value="{Binding ElementName=CustomProgressBarUC, Path=ProgressBarValue, Mode=OneWay}"
                     Maximum="100"
                     Height="8"
                     Width="300"
                     Foreground="DarkBlue"
                     Background="LightGray"
                     BorderBrush="LightGray" />
    </StackPanel>

</UserControl>
Enter fullscreen mode Exit fullscreen mode

In the above XAML file, we have 'StackPanel' to hold our progress bar and percentage text. Inside the 'StackPanel', we'll have a 'Grid' to hold the progress bar.

We've added two column definitions to the 'Grid'. The first column's width is bound to the 'ProgressBarValue' property of our user control, and we've used the 'ProgressBarValueToWidthConverter' converter to convert the progress bar value to a width. The second column's width is also bound to the 'ProgressBarValue; property, but we've used the 'InverseProgressBarValueToWidthConverter' converter to convert the inverse value of the progress bar to a width.

We've also added a 'TextBlock' to show the progress percentage. Its 'Text' property is bound to the 'ProgressBarValue' property, and we've used a 'StringFormat' to display the value as a percentage with no decimal places.

Finally, we'll add a 'ProgressBar' control to the 'StackPanel'. We'll bind its Value property to the 'ProgressBarValue' property of our user control, and we'll set its Minimum and Maximum values to 0 and 100, respectively.

  • CustomProgressBar.xaml.cs
public partial class Progressbar : UserControl
{
    public Progressbar()
    {
        InitializeComponent();
        ProgressBarValue = 0;
    }

    public double ProgressBarValue
    {
        get => (double)GetValue(ProgressBarValueProperty);
        set => SetValue(ProgressBarValueProperty, value);
    }

    // Using a DependencyProperty as the backing store for ProgressBarValue.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ProgressBarValueProperty =
        DependencyProperty.Register(nameof(ProgressBarValue), typeof(double), typeof(Progressbar));
}
Enter fullscreen mode Exit fullscreen mode

The above CustomProgressBar has a public property called 'ProgressBarValue' which is backed by a DependencyProperty. This property allows the value of the progress bar to be set and updated from the main project.

Conclusion

With these elements in place, we can create a fully functional custom progress bar with a moving percentage in WPF, simply by using the UserControl that contains the progress bar, as a separate library in our main project.

Progress Bar

Source Code: https://github.com/RupeshGhosh10/CustomProgressBar

Top comments (0)