慕的地10843
返回代码:class MyCustomConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return new Thickness(0, 0, -(double)value, 0); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }}模板:<ControlTemplate TargetType="ProgressBar"> <ControlTemplate.Resources> <local:MyCustomConverter x:Key="sttc"/> </ControlTemplate.Resources> <Border BorderBrush="#D9DCE1" BorderThickness="0" Background="#FF0C0B0B" CornerRadius="0" Padding="0" ClipToBounds="True"> <Grid x:Name="PART_Track" Margin="{TemplateBinding Height ,Converter={StaticResource sttc}}"> <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#FF2BA9FF" RenderTransformOrigin="0,0"> <Rectangle.RenderTransform> <TransformGroup> <SkewTransform AngleX="-45"/> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> </Grid> </Border></ControlTemplate>注意:如果高度是固定的,则不需要转换器,将边距设置为固定的厚度。转换器仅适用于自动调整大小。
慕丝7291255
第三种方法是使用Path它Data被设计为逆时针倾斜变换并且它RenderTransform是顺时针的SkewTransform。这样,移动指示器确实完全达到了 100%。<ControlTemplate x:Key="ProgressBarPath" TargetType="ProgressBar"> <Viewbox Stretch="Fill"> <Grid HorizontalAlignment="Left" Margin="-5 0"> <Path Stretch="None" x:Name="PART_Track" Fill="#0C0B0B" RenderTransformOrigin="0,0.5" StrokeMiterLimit="1" Data="M 0,0 l 150,0 10,10 -150,0 z"> <Path.RenderTransform> <SkewTransform AngleX="-45" /> </Path.RenderTransform> </Path> <Path Stretch="None" x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#29AAE1" RenderTransformOrigin="0,0.5" StrokeMiterLimit="1" Data="M 0,0 l 150,0 10,10 -150,0 z"> <Path.RenderTransform> <SkewTransform AngleX="-45" /> </Path.RenderTransform> </Path> </Grid> </Viewbox></ControlTemplate>2018年的两种方法和这个方法的比较:以上 APNG 的完整代码:MainWindow.xaml:<Window x:Class="StackOverFlowTest.MainWindow" 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:local="clr-namespace:StackOverFlowTest" mc:Ignorable="d" Title="MainWindow" Height="250" Width="550"> <Window.Resources> <!-- ProgressBar templates with skewed Indicator: Reference: "How do I make a custom shape of progressbar in wpf?" https://stackoverflow.com/questions/52250531/how-do-i-make-a-custom-shape-of-progressbar-in-wpf --> <!-- ProgressBar with skewed Rectangle Advantages: - Moving Indicator supports transparent background - Moving Indicator shows no artifacts Disadvantage: - Moving Indicator doesn't completely reach 100% Code from "Mr. Squirrel.Downy": https://stackoverflow.com/a/52252590 --> <ControlTemplate x:Key="ProgressBarRectangle" TargetType="ProgressBar"> <Border BorderBrush="#D9DCE1" BorderThickness="0" Background="#FF0C0B0B" CornerRadius="0" Padding="0" ClipToBounds="True"> <Grid x:Name="PART_Track"> <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#2BA9FF" RenderTransformOrigin="0,0"> <Rectangle.RenderTransform> <TransformGroup> <SkewTransform AngleX="-45"/> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> </Grid> </Border> </ControlTemplate> <!-- ProgressBar with right-aligned Polygon Disadvantages: - Moving Indicator doesn't completely reach 100% - Moving Indicator doesn't support transparent background (Polygon must hide Indicator) - Moving Indicator shows artifacts when ProgressBar is set to large width (Polygon isn't able to hide Indicator accurately) - <ControlTemplate> has to be adjusted if height of ProgressBar exceeds height of Polygon Code from "mm8": https://stackoverflow.com/a/52279788 --> <ControlTemplate x:Key="ProgressBarPolygon" TargetType="ProgressBar"> <Border BorderBrush="#D9DCE1" BorderThickness="0" Background="#FF0C0B0B" CornerRadius="0" Padding="0"> <Grid x:Name="PART_Track"> <Grid x:Name="PART_Indicator" HorizontalAlignment="Left" Background="#FF2BA9FF"> <Polygon Points="0,32 32,0 32,32" Stroke="#FF0C0B0B" Fill="#FF0C0B0B" HorizontalAlignment="Right" /> </Grid> </Grid> </Border> </ControlTemplate> <!-- ProgressBar with skewed Path Advantages: - Moving Indicator completely reaches 100% - Moving Indicator supports transparent background - Moving Indicator shows no artifacts Disadvantage: - <ControlTemplate> has to be adjusted if proportion (width-height-ratio) of ProgressBar differs from the two ones in PathGeometry, otherwise the moving Indicator alters its angle. How2: Create PathGeometry ( <Path Data="..."> ) contrary to planed skew angle to skew PART_Indicator to desired angle. Example: By default "PART_Indicator" is always vertical. To solely give the Indicator a 45° clockwise 'rotation' ("/"), design your Path as a 45° anti-clockwise skewed Path. For a simple Path like in these ProgressBars, you can quite easily do mental arithmetic. For more complex Path Data, you can use calculation methods in CS code... --> <ControlTemplate x:Key="ProgressBarPath" TargetType="ProgressBar"> <Viewbox Stretch="Fill"> <Grid HorizontalAlignment="Left" Margin="-5 0"> <Path Stretch="None" x:Name="PART_Track" Fill="#0C0B0B" RenderTransformOrigin="0,0.5" StrokeMiterLimit="1" Data="M 0,0 l 150,0 10,10 -150,0 z"> <Path.RenderTransform> <SkewTransform AngleX="-45" /> </Path.RenderTransform> </Path> <Path Stretch="None" x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#29AAE1" RenderTransformOrigin="0,0.5" StrokeMiterLimit="1" Data="M 0,0 l 150,0 10,10 -150,0 z"> <Path.RenderTransform> <SkewTransform AngleX="-45" /> </Path.RenderTransform> </Path> </Grid> </Viewbox> </ControlTemplate> </Window.Resources> <StackPanel Orientation="Vertical" Background="#464646"> <!--ProgressBar with Rectangle, "Mr. Squirrel.Downy":--> <Grid HorizontalAlignment="Center" Margin="0 27 0 0"> <ProgressBar Template="{StaticResource ProgressBarRectangle}" Width="480" Height="32" Value="{Binding ElementName=Progress, Path=Value}" /> <Label Content="<Rectangle> + <SkewTansform> (by Mr. Squirrel Downy)" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FFFFFF" /> <Label Content="{Binding ElementName=Progress, Path=Value}" ContentStringFormat="{}{0} %" Padding="0" HorizontalAlignment="Right" VerticalAlignment="Center" FontStyle="Italic" Margin="0 0 10 0" Foreground="#808080" /> </Grid> <!--ProgressBar with Polygon, "mm8":--> <Grid HorizontalAlignment="Center" Margin="0 4 0 0"> <ProgressBar Template="{StaticResource ProgressBarPolygon}" Width="480" Height="32" Value="{Binding ElementName=Progress, Path=Value}" /> <Label Content="<Polygon HorizontalAlignment="Right" /> (by mm8)" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FFFFFF" /> <Label Content="{Binding ElementName=Progress, Path=Value}" ContentStringFormat="{}{0} %" Padding="0" HorizontalAlignment="Right" VerticalAlignment="Center" FontStyle="Italic" Margin="0 0 10 0" Foreground="#808080" /> </Grid> <!--ProgressBar with Path:--> <Grid HorizontalAlignment="Center" Margin="0 4 0 0"> <ProgressBar Template="{StaticResource ProgressBarPath}" Width="480" Height="32" Value="{Binding ElementName=Progress, Path=Value}" /> <Label Content="<Path> + <SkewTransform>" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FFFFFF" /> <Label Content="{Binding ElementName=Progress, Path=Value}" ContentStringFormat="{}{0} %" Padding="0" HorizontalAlignment="Right" VerticalAlignment="Center" FontStyle="Italic" Margin="0 0 10 0" Foreground="#808080" /> </Grid> <Slider Name="Progress" Margin="0 35 0 0" Minimum="0" Maximum="100" Width="480" IsSnapToTickEnabled="True" TickFrequency="1" /> </StackPanel></Window>为了完整起见,在后面的代码中计算复杂路径数据的示例(上述 XAML 不需要):MainWindow.xaml.cs:using System.Diagnostics;using System.Globalization;using System.Windows;using System.Windows.Media;namespace StackOverFlowTest{ /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // Instantiate and initialize variable for normal Path Data without transformation: Geometry geo = Geometry.Parse("M 0,0 l 150,0 0,10 -150,0 z"); // Instantiate and initialize variable for desired shearing/transvection // (use opposite transformation to the one in the ControlTemplate): SkewTransform skewT = new SkewTransform(45, 0); // In case of additional transformations: // Instantiate and initialize variable for desired translation: //TranslateTransform transT = new TranslateTransform(-31.89, 0); // Instantiate variable for all transformations, as you have to apply all transformation at once: //TransformGroup tG = new TransformGroup(); //tG.Children.Add(skewT); //tG.Children.Add(transT); // Create a clone of of your Geometry object, // since in order to apply a transform, geometry must not be readonly: Geometry geoClone = geo.Clone(); // Apply transformation: geoClone.Transform = skewT; // For multiple transformations: //geoClone.Transform = tG; // Calculate new Path Data: string result = geoClone.GetFlattenedPathGeometry(0.001, ToleranceType.Relative).ToString(CultureInfo.InvariantCulture); //var result = geoClone.GetFlattenedPathGeometry(0.001, ToleranceType.Relative).ToString().Replace(",", ".").Replace(";", ","); // Return new Path Data: Trace.WriteLine(this + ": " + result); // Returns: M0,0L150,0 160,10 10,10 0,0z // Note that returned values are absolute values. // Identical Path Data in relative coordinates (meaning offset values to respective previous point): // M 0,0 l 150,0 10,10 -150,0 z } }}