Tommy
Tommy

Reputation: 71

Progressbar that changes style based on percentage complete

I am new to WPF and have not been able to find the solution to this yet.

We are trying to make a UserControl that provides a progressbar that will change its style as the percentage goes up (basically red when like less then 50%, yellow to 30%, etc.)

The control seems to work exceot for the style getting updated. When the window is first brought up the value is always 0 even if the progressbar is being started at 50% or so. To me it seems I have messed up the PropertyChanged code or not connected the data up right somewhere. Here is the code so far:

XAML file comsuming the UserControl (TaskListStatus.xaml)

    <ssw:ColoredProgressBar x:Name="pbCompleted" Value="{Binding PercentCompleted}" Height="40"/>

ColoredProgressBar.xaml:

    <UserControl.Resources>
        <this:ProgressBarStyleConverter x:Key="pbStyleConverter"/>
        <!-- Progress Bar Styles-->
        ........
    </UserControl.Resources>
    <Grid>
        <ProgressBar x:Name="pb" Value="{Binding Path=Value, ElementName=coloredBar}">
            <ProgressBar.Style>
                <Binding Converter="{StaticResource pbStyleConverter}"
                        RelativeSource="{RelativeSource Self}"/>
            </ProgressBar.Style>
        </ProgressBar>
    </Grid>

ColoredProgressBar.xaml.cs

    public partial class ColoredProgressBar : UserControl, INotifyPropertyChanged {
        public ColoredProgressBar() {
            InitializeComponent();
        }
        public static DependencyProperty ValueProperty =
                  DependencyProperty.Register("Value", typeof(double),
                  typeof(ColoredProgressBar), new PropertyMetadata(null));
        public double Value {
            get { return Convert.ToDouble(GetValue(ValueProperty)); }
            set {
                SetValue(ValueProperty, value);
                if (PropertyChanged != null) {
                    PropertyChanged(this, new PropertyChangedEventArgs("Value"));
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

ProgressBarStyleConverter.cs

    public class ProgressBarStyleConverter : IValueConverter {
        private const int RED_CUTOFF = 40;
        private const int YELLOW_CUTOFF = 100;
        private enum ProgressBarColor {
            Green,
            Yellow,
            Red
        }
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            FrameworkElement targetElement = value as FrameworkElement;
            double progressBarValue = ((ProgressBar)targetElement).Value;
            string styleName = "AeroProgressBarStyle";
            ProgressBarColor color;
            if (progressBarValue < RED_CUTOFF) {
                color = ProgressBarColor.Red;
            } else if (progressBarValue < YELLOW_CUTOFF) {
                color = ProgressBarColor.Yellow;
            } else {
                color = ProgressBarColor.Green;
            }
            switch (color) {
                case ProgressBarColor.Green:
                    styleName = "AeroProgressBarStyle"; break;
                case ProgressBarColor.Yellow:
                    styleName = "YellowAeroProgressBarStyle"; break;
                case ProgressBarColor.Red:
                    styleName = "RedAeroProgressBarStyle"; break;
            }
            return (Style)targetElement.TryFindResource(styleName);
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            return null;
        }
    }

If anyone can help it would be greatly appreciated.

Upvotes: 2

Views: 432

Answers (2)

Tommy
Tommy

Reputation: 71

So far this is the way we have gotten it to work. I am not 100% sure this is the ideal way but it does work:

ColoredProgressBar.xaml:

    <UserControl.Resources>
        <this:ProgressBarStyleConverter x:Key="pbStyleConverter"/>
        <!-- Progress Bar Styles-->
        ........
    </UserControl.Resources>
    <Grid>
        <ProgressBar x:Name="pb" Value="{Binding Path=Value, ElementName=coloredBar}">
            <ProgressBar.Style>
                <MultiBinding Converter="{StaticResource pbStyleConverter}">
                    <Binding RelativeSource="{RelativeSource Self}" />
                    <Binding ElementName="coloredBar" Path="Value" />
                </MultiBinding>
            </ProgressBar.Style>
        </ProgressBar>
    </Grid>

We could not figure out how to get the binding down to a single binding. The reason we have to pass in Self is because that is where all of the temples are defined for setting up the color. I tried passing Self in as a ConverterParameter but I could never seem to get it to work. So by passing it in as a MultiBinding we can get to self and the temples defined there and since value is passed in, when value updates, it updates the temple of the progressbar.

Upvotes: 1

Joe Strommen
Joe Strommen

Reputation: 1234

Bind the style to the Value property of the ProgressBar rather than the ProgressBar itself. So add a Path=Value attribute to the binding, and modify the converter code accordingly.

Upvotes: 0

Related Questions