编辑进度条形状 wpf

Edit progress bar shape wpf

我有一个进度条,其 ControlTemplate 如下所示,我想将进度条的值设置为一个数字,以便进度更新为该值。我参考了关于此 but don't know how to use the converter for my scenario. I also checked this 的公认答案,并且编辑 Rect 工作正常。但是我不能使用 Rectangle Geomerty。请帮忙。 (如果我删除下面 xaml 中的注释路径,它会创建一些填充容器的值。)这是我删除注释 xaml.

时的屏幕截图

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

如果条形是矩形,您可以利用 ProgressBar 的 built-in 机制改变形状以显示当前值。否则,您将需要自己实现该机制。

我认为 会对此给出很好的提示。比方说,您创建了一个名为“FlaskProgressBar”的自定义 ProgressBar。在这个 ProgressBar 的 CustomTemplate 中,

  1. 为轮廓的路径定义一个PathGeometry,并设置其Stroketwo-colored笔刷来绘制轮廓。

  2. 为空白区域的路径添加一个RectangleGeometry,并使用轮廓路径的Data裁剪。

  3. 为显示当前值的填充区域的路径添加一个 RectangleGeometry 并裁剪它。将 RectangleGeomety 命名为“PART_Content”,以便可以从 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>

在“FlaskProgressBar”中,找到名为“PART_Content”的 RectangleGeometry,当当前值更改时,更改其 RectY 值以将其向上或向下移动。

[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);
        }
    }
}

这个 ProgresBar 看起来像这样:

轮廓Path的PathGeometry实际设计完全由您决定。