Progress bar with dynamic updating of text and text

I have a progressbar whose text changes dynamically. I want to update its appearance in such a way that as soon as progress reaches the text, the color of the text should be updated. Something like that. enter image description here

I need the text color of the text (black) that appears above the blue background, should automatically change to white. However, text with a white background should remain black.

+28
progress-bar wpf
Mar 02 '11 at 13:05
source share
3 answers

Here is one way to do this using a modified version of the ProgressBars default Template . It contains two TextBlocks

  • The first TextBlock is black
  • The second TextBlock is white. This TextBlock has the width of the full control and Clip set to the width of the progress part.

enter image description here

The text of the ProgressBar bound to the Tag property. Used like that.

 <ProgressBar TextBlock.FontWeight="Bold" Tag="ProgressBar Text" Foreground="Blue" Style="{DynamicResource MyProgressBarStyle}"/> 

MyProgressBarStyle

 <LinearGradientBrush x:Key="ProgressBarBackground" EndPoint="1,0" StartPoint="0,0"> <GradientStop Color="#BABABA" Offset="0"/> <GradientStop Color="#C7C7C7" Offset="0.5"/> <GradientStop Color="#BABABA" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarBorderBrush" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#B2B2B2" Offset="0"/> <GradientStop Color="#8C8C8C" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarGlassyHighlight" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#50FFFFFF" Offset="0.5385"/> <GradientStop Color="#00FFFFFF" Offset="0.5385"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarTopHighlight" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#80FFFFFF" Offset="0.05"/> <GradientStop Color="#00FFFFFF" Offset="0.25"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarIndicatorAnimatedFill" EndPoint="1,0" StartPoint="0,0"> <GradientStop Color="#00FFFFFF" Offset="0"/> <GradientStop Color="#60FFFFFF" Offset="0.4"/> <GradientStop Color="#60FFFFFF" Offset="0.6"/> <GradientStop Color="#00FFFFFF" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarIndicatorDarkEdgeLeft" EndPoint="1,0" StartPoint="0,0"> <GradientStop Color="#0C000000" Offset="0"/> <GradientStop Color="#20000000" Offset="0.3"/> <GradientStop Color="#00000000" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="ProgressBarIndicatorDarkEdgeRight" EndPoint="1,0" StartPoint="0,0"> <GradientStop Color="#00000000" Offset="0"/> <GradientStop Color="#20000000" Offset="0.7"/> <GradientStop Color="#0C000000" Offset="1"/> </LinearGradientBrush> <RadialGradientBrush x:Key="ProgressBarIndicatorLightingEffectLeft" RadiusY="1" RadiusX="1" RelativeTransform="1,0,0,1,0.5,0.5"> <GradientStop Color="#60FFFFC4" Offset="0"/> <GradientStop Color="#00FFFFC4" Offset="1"/> </RadialGradientBrush> <LinearGradientBrush x:Key="ProgressBarIndicatorLightingEffect" EndPoint="0,0" StartPoint="0,1"> <GradientStop Color="#60FFFFC4" Offset="0"/> <GradientStop Color="#00FFFFC4" Offset="1"/> </LinearGradientBrush> <RadialGradientBrush x:Key="ProgressBarIndicatorLightingEffectRight" RadiusY="1" RadiusX="1" RelativeTransform="1,0,0,1,-0.5,0.5"> <GradientStop Color="#60FFFFC4" Offset="0"/> <GradientStop Color="#00FFFFC4" Offset="1"/> </RadialGradientBrush> <LinearGradientBrush x:Key="ProgressBarIndicatorGlassyHighlight" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#90FFFFFF" Offset="0.5385"/> <GradientStop Color="#00FFFFFF" Offset="0.5385"/> </LinearGradientBrush> <Style x:Key="MyProgressBarStyle" TargetType="{x:Type ProgressBar}"> <Setter Property="Foreground" Value="#01D328"/> <Setter Property="Background" Value="{StaticResource ProgressBarBackground}"/> <Setter Property="BorderBrush" Value="{StaticResource ProgressBarBorderBrush}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ProgressBar}"> <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true"> <TextBlock Text="{TemplateBinding Tag}" Grid.ZIndex="2" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="{TemplateBinding Tag}" Grid.ZIndex="3" Foreground="White" Width="{Binding ElementName=rectangle, Path=ActualWidth}" TextAlignment="Center" HorizontalAlignment="Stretch" VerticalAlignment="Center"> <TextBlock.Clip> <RectangleGeometry> <RectangleGeometry.Rect> <MultiBinding Converter="{StaticResource RectConverter}"> <Binding ElementName="Indicator" Path="ActualWidth"/> <Binding ElementName="Indicator" Path="ActualHeight"/> </MultiBinding> </RectangleGeometry.Rect> </RectangleGeometry> </TextBlock.Clip> </TextBlock> <Rectangle x:Name="rectangle" Fill="{TemplateBinding Background}" RadiusY="2" RadiusX="2"/> <Border Background="{StaticResource ProgressBarGlassyHighlight}" CornerRadius="2" Margin="1"/> <Border BorderBrush="#80FFFFFF" BorderThickness="1,0,1,1" Background="{StaticResource ProgressBarTopHighlight}" Margin="1"/> <Rectangle x:Name="PART_Track" Margin="1"/> <Decorator x:Name="PART_Indicator" HorizontalAlignment="Left" Margin="1"> <Grid x:Name="Foreground"> <Rectangle x:Name="Indicator" Fill="{TemplateBinding Foreground}"/> <Grid x:Name="Animation" ClipToBounds="true"> <Rectangle x:Name="PART_GlowRect" Fill="{StaticResource ProgressBarIndicatorAnimatedFill}" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100"/> </Grid> <Grid x:Name="Overlay"> <Grid.ColumnDefinitions> <ColumnDefinition MaxWidth="15"/> <ColumnDefinition Width="0.1*"/> <ColumnDefinition MaxWidth="15"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Rectangle x:Name="LeftDark" Fill="{StaticResource ProgressBarIndicatorDarkEdgeLeft}" Margin="1,1,0,1" RadiusY="1" RadiusX="1" Grid.RowSpan="2"/> <Rectangle x:Name="RightDark" Grid.Column="2" Fill="{StaticResource ProgressBarIndicatorDarkEdgeRight}" Margin="0,1,1,1" RadiusY="1" RadiusX="1" Grid.RowSpan="2"/> <Rectangle x:Name="LeftLight" Grid.Column="0" Fill="{StaticResource ProgressBarIndicatorLightingEffectLeft}" Grid.Row="2"/> <Rectangle x:Name="CenterLight" Grid.Column="1" Fill="{StaticResource ProgressBarIndicatorLightingEffect}" Grid.Row="2"/> <Rectangle x:Name="RightLight" Grid.Column="2" Fill="{StaticResource ProgressBarIndicatorLightingEffectRight}" Grid.Row="2"/> <Border x:Name="Highlight1" Background="{StaticResource ProgressBarIndicatorGlassyHighlight}" Grid.ColumnSpan="3" Grid.RowSpan="2"/> <Border x:Name="Highlight2" Background="{StaticResource ProgressBarTopHighlight}" Grid.ColumnSpan="3" Grid.RowSpan="2"/> </Grid> </Grid> </Decorator> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="Orientation" Value="Vertical"> <Setter Property="LayoutTransform" TargetName="TemplateRoot"> <Setter.Value> <RotateTransform Angle="-90"/> </Setter.Value> </Setter> </Trigger> <Trigger Property="IsIndeterminate" Value="true"> <Setter Property="Visibility" TargetName="LeftDark" Value="Collapsed"/> <Setter Property="Visibility" TargetName="RightDark" Value="Collapsed"/> <Setter Property="Visibility" TargetName="LeftLight" Value="Collapsed"/> <Setter Property="Visibility" TargetName="CenterLight" Value="Collapsed"/> <Setter Property="Visibility" TargetName="RightLight" Value="Collapsed"/> <Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/> </Trigger> <Trigger Property="IsIndeterminate" Value="false"> <Setter Property="Background" TargetName="Animation" Value="#80B5FFA9"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> 

Rectectonverter

 public class RectConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double width = (double)values[0]; double height = (double)values[1]; return new Rect(0, 0, width, height); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 
+45
Mar 02 2018-11-21T00:
source share
— -

Here is the solution in Silverlight, but it is easy to convert it to WPF.

I use a linear gradient brush to change the color of the text in the text block, I created a user control with a progress bar and a text block, called "SpecialProgressBar" on it

Here's the XAML:

 <UserControl x:Class="TestSilverlightApplication.SpecialProgressBar" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" x:Name="specialProgressBar"> <Canvas Width="Auto" Height="Auto"> <ProgressBar Name="progressBar" IsIndeterminate="False" Background="White" Foreground="Blue" Height="{Binding Height, ElementName=specialProgressBar}" Width="{Binding Width, ElementName=specialProgressBar}" /> <TextBlock x:Name="textBlock" FontWeight="Bold" Text="xxx of yyy" /> </Canvas> </UserControl> 

And here is the code:

 using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace TestSilverlightApplication { public partial class SpecialProgressBar : UserControl { private Point _textBlockPosition; private readonly LinearGradientBrush _linearGradientBrush; private readonly GradientStop _gradientStop; public SpecialProgressBar() { InitializeComponent(); // will be changing this gradient stop as the progress bar value changes _gradientStop = new GradientStop { Color = Colors.Black, Offset = 0 }; // the default brush we want to start with, // you might want to play with the start point x value to get the effect you want _linearGradientBrush = new LinearGradientBrush { StartPoint = new Point(-0.2, 0.5), EndPoint = new Point(1, 0.5), GradientStops = new GradientStopCollection { _gradientStop, new GradientStop { Color = Colors.Black, Offset = 1 } } }; // set the brush to the text block textBlock.Foreground = _linearGradientBrush; Loaded += new RoutedEventHandler(SpecialProgressBar_Loaded); progressBar.ValueChanged += new RoutedPropertyChangedEventHandler<double>(progressBar_ValueChanged); } private void SpecialProgressBar_Loaded(object sender, RoutedEventArgs e) { // center text block on top of the progress bar _textBlockPosition = new Point(progressBar.Width / 2 - textBlock.ActualWidth / 2, progressBar.Height / 2 - textBlock.ActualHeight / 2); textBlock.SetValue(Canvas.LeftProperty, _textBlockPosition.X); textBlock.SetValue(Canvas.TopProperty, _textBlockPosition.Y); } private void progressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // print out the value in the text block textBlock.Text = string.Concat(e.NewValue, " of ", progressBar.Maximum); // get the value relative to the size of the progress bar var x = e.NewValue / progressBar.Maximum * progressBar.Width; // if the value is equal to or greater than the position of the text block on the canvas (on the progress bar) // then we want to change the gradient offset and color. if (x >= _textBlockPosition.X) { _gradientStop.Offset += 0.1 * textBlock.ActualWidth / progressBar.Width; _gradientStop.Color = Colors.White; // when we pass the end of the text block we don't need the gradient any more, // replace it with a solid white color if (_gradientStop.Offset >= 1) { textBlock.Foreground = new SolidColorBrush(Colors.White); } } } } } 

The final step is to add the user control to the page (or other user control).

 <UserControl x:Class="TestSilverlightApplication.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:TestSilverlightApplication="clr-namespace:TestSilverlightApplication" mc:Ignorable="d"> <Grid> <TestSilverlightApplication:SpecialProgressBar x:Name="specialProgressBar" Width="200" Height="40" /> </Grid> </UserControl> 

And to check this, I added a timer to change the value of the execution line:

 using System; using System.Windows.Controls; using System.Windows.Threading; namespace TestSilverlightApplication { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); this.Loaded += new System.Windows.RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e) { var timer = new DispatcherTimer(); timer.Tick += (s, args) => specialProgressBar.progressBar.Value += 1; timer.Interval = new TimeSpan(1000000); timer.Start(); } } } 

It looks like this:

enter image description here

This is a quick and dirty decision, but it is the beginning, I think. Hope this helps.

+7
Mar 02 2018-11-21T00:
source share

Although I used all the solution provided by Meleak, but here is how I did it.

 <ProgressBar x:Name="SummaryProgressBar" BorderBrush="Black" BorderThickness="1" Background="LightGray" FlowDirection="LeftToRight" Maximum="1" MinWidth="200" Width="Auto"> <ProgressBar.Value> <MultiBinding Converter="{StaticResource ArithmeticConverter}" Mode="OneWay"> <Binding Path="ABCCollectionView.Count"/> <Binding Source="{StaticResource DivideArithmeticSymbol}" /> <Binding Path="XYZCollectionView.Count"/> </MultiBinding> </ProgressBar.Value> </ProgressBar> <!-- Black Progress Bar Text --> <TextBlock x:Name="TextBlockBlack" VerticalAlignment="Center" TextAlignment="Center" HorizontalAlignment="Stretch" FontWeight="Bold" Foreground="Black" Text="{Binding SummaryText}" Width="{Binding ElementName=SummaryProgressBar, Path=ActualWidth}"></TextBlock> <!-- White Progress Bar Text --> <TextBlock x:Name="TextBlockWhite" VerticalAlignment="Center" TextAlignment="Center" HorizontalAlignment="Stretch" FontWeight="Bold" Foreground="White" Text="{Binding SummaryText}" Width="{Binding ElementName=SummaryProgressBar, Path=ActualWidth}"> <TextBlock.Clip> <RectangleGeometry> <RectangleGeometry.Rect> <MultiBinding Converter="{StaticResource ProgressBarFillToRectConverter}"> <Binding ElementName="SummaryProgressBar" Path="Value"/> <Binding ElementName="TextBlockWhite" Path="ActualWidth" /> <Binding ElementName="TextBlockWhite" Path="ActualHeight"/> </MultiBinding> </RectangleGeometry.Rect> </RectangleGeometry> </TextBlock.Clip> </TextBlock> 

and here is the converter

  /// <summary> /// Converts the ProgressBar Fill percentage width to a Rectangle whose width is calculated by multiplying Fill Percentage to Actual Width of control. Height is passed too. /// Note: This converter is used in showing WHITE & BLACK text on progress bar. Also use White textblock next to Black not reverse in XAML. /// </summary> public class ProgressBarFillToRectConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (values != null && values[0] != null && values[1] != null && values[2] != null) { double progressBarFillPercentage = (double)values[0]; double textBlockActualyWidth = (double)values[1]; double textBlockHeight = (double)values[2]; return new Rect(0, 0, progressBarFillPercentage * textBlockActualyWidth, textBlockHeight); // ProgressBarFillWidth is calculated by multiplying Fill // percentage with actual width } return new Rect(0, 0, 0, 0); // Default Zero size rectangle } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 
+5
Mar 03 '11 at 12:41
source share



All Articles