I have a progress bar whose ControlTemplate is as follows and I want to set the value of the progress bar to a number so the progress updates to that value. I refered to the accpeted answer on this
<Window.Resources>
<ControlTemplate x:Key="ProgressBarPath" TargetType="ProgressBar">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="Test" Width="100" Height="100" Canvas.Left="0" Canvas.Top="0">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas.Resources/>
<Canvas Name="g40">
<!--<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path28"
Fill="Red">
<Path.Data>
<PathGeometry Figures="M35.1 57h-.2l-2.1 2.6-10 12.5c-2.1 2.7-5.2 6.2-4.3 9.5 1.7 6.1 7.6 6.1 11.8 6.1H50V57H35.7z" FillRule="NonZero"/>
</Path.Data>
</Path>-->
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path30" Fill="#FF333333">
<Path.Data>
<PathGeometry Figures="M30.8 87.7c-4.2 0-10.1 0-11.8-6.1-.9-3.3 2.2-6.8 4.3-9.5l10-12.5 2.1-2.6 5-6.3 1.6-2.1 1-1.3V17.5l-2.2-.2c-1.2-.1-2.1-1.1-2.1-2.4 0-1.3 1.1-2.4 2.4-2.4H50v-5h-9.2c-.9 0-1.7.3-2.2.4-2.8 1-4.9 3.8-4.9 7 0 3 1.8 5.6 4.4 6.7v24.2L29.3 57 16.7 72.8c-2.9 3.7-3.5 8.6-1.4 12.8 2 4.2 6.2 6.9 10.9 6.9H50v-4.8H30.8z" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path32" Fill="#FF333333">
<Path.Data>
<PathGeometry Figures="M35.4 57l-2.1 2.6 2.1-2.6z" FillRule="EvenOdd"/>
</Path.Data>
</Path>
<!--<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path34"
Fill="Red">
<Path.Data>
<PathGeometry Figures="M64.3 57H50v30.7h19.2c4.2 0 10.7-.7 11.8-6.1.7-3.4-2.2-6.8-4.3-9.5l-10-12.5-2.1-2.6h-.3z"
FillRule="NonZero"/>
</Path.Data>
</Path>-->
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path36" Fill="#FF666666">
<Path.Data>
<PathGeometry Figures="M84.7 85.6c2-4.2 1.5-9.1-1.4-12.8L70.7 57l-8.8-11.1V21.7c2.6-1.1 4.4-3.8 4.4-6.8 0-4.1-3.3-7.4-7.4-7.4H50v5h8.9c1.3 0 2.4 1.1 2.4 2.5 0 1.2-.9 2.2-2.1 2.3l-2.2.2v29.8l1 1.3 1.6 2.1 7.1 8.9 10 12.5c2.1 2.7 5 6.1 4.3 9.5-1.1 5.3-7.6 6.1-11.8 6.1H50v4.8h23.9c4.6 0 8.8-2.6 10.8-6.9z" FillRule="NonZero"/>
</Path.Data>
</Path>
<!--Unknown tag: metadata-->
</Canvas>
</Canvas>
</Viewbox>
</ControlTemplate>
</Window.Resources>
<Grid HorizontalAlignment="Center" Margin="0 4 0 0">
<ProgressBar Template="{StaticResource ProgressBarPath}" Width="480" Height="102" Value="40" />
</Grid>
</Window>
CodePudding user response:
If the bar is a rectangular shape, you can utilize the built-in mechanism of ProgressBar to change the shape to show current value. Otherwise, you will need to implement the mechanism on your own.
I think Clemens's answer will give a good hint for this. Let's say, you create a custom ProgressBar named "FlaskProgressBar". In the CustomTemplate for this ProgressBar,
Define a PathGeometry for the Path of outline and set its
Stroke
two-colored Brush to draw outline.Add a RectangleGeometry for the Path of vacant area and crop it using the
Data
of the Path of outline.Add a RectangleGeometry for the Path of filled area which shows current value and crop it as well. Name the RectangleGeomety "PART_Content" so that it can be found from the code-behind.
<ControlTemplate x:Key="FlaskProgressBarTemplate" TargetType="{x:Type local:FlaskProgressBar}">
<ControlTemplate.Resources>
<LinearGradientBrush x:Key="OutlineBrush" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#FF333333" Offset="0.5"/>
<GradientStop Color="#FF666666" Offset="0.5"/>
<GradientStop Color="#FF666666" Offset="1"/>
</LinearGradientBrush>
</ControlTemplate.Resources>
<Grid>
<Grid Margin="6">
<!-- Draw outline -->
<Path x:Name="Outline"
StrokeThickness="8"
Stroke="{StaticResource OutlineBrush}">
<Path.Data>
<PathGeometry Figures="M 20,0 L 20,60 0,100 60,100 40,60 40,0 Z"/>
</Path.Data>
</Path>
<!-- Draw vacent area -->
<Path Data="{Binding Data, ElementName=Outline}"
Fill="{TemplateBinding Background}">
<Path.Clip>
<RectangleGeometry Rect="0,0,60,100"/>
</Path.Clip>
</Path>
<!-- Draw filled area -->
<Path Data="{Binding Data, ElementName=Outline}"
Fill="{TemplateBinding Foreground}">
<Path.Clip>
<RectangleGeometry x:Name="PART_Content" Rect="0,100,60,100"/>
</Path.Clip>
</Path>
</Grid>
</Grid>
</ControlTemplate>
In the "FlaskProgressBar", find the RectangleGeometry named "PART_Content" and when current value is changed, change Y
value of its Rect
to move it up or down.
[TemplatePart(Name = "PART_Content", Type = typeof(RectangleGeometry))]
public class FlaskProgressBar : ProgressBar
{
public FlaskProgressBar() : base()
{
ValueProperty.OverrideMetadata(typeof(FlaskProgressBar),
new FrameworkPropertyMetadata(0D, (d, e) => SetValue((FlaskProgressBar)d, (double)e.NewValue)));
}
private RectangleGeometry? _content;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_content = this.GetTemplateChild("PART_Content") as RectangleGeometry;
SetValue(this, Value);
}
private static void SetValue(FlaskProgressBar instance, double value)
{
if (instance._content is not null)
{
var rect = instance._content.Rect;
instance._content.Rect = new Rect(rect.X, rect.Height - value, rect.Width, rect.Height);
}
}
}
This ProgresBar looks like this:
The actual design of PathGeometry for the Path of outline is all up to you.