Home > Mobile >  Edit progress bar shape wpf
Edit progress bar shape wpf

Time:03-16

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 enter image description here

<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,

  1. Define a PathGeometry for the Path of outline and set its Stroke two-colored Brush to draw outline.

  2. Add a RectangleGeometry for the Path of vacant area and crop it using the Data of the Path of outline.

  3. 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:

enter image description here

The actual design of PathGeometry for the Path of outline is all up to you.

  • Related