【问题标题】:How do I make a custom shape of progressbar in wpf?如何在 wpf 中制作自定义形状的进度条?
【发布时间】:2018-09-10 03:03:33
【问题描述】:

好的,我将自定义一个进度条或在 C# WPF 中加载,而不是矩形,它的末尾应该有一些小的锐度。 看起来像这样

加载完成后锐度消失

目前,这就是我所做的。

如何实现自定义加载栏?

这是我的代码,XAML

<Window x:Class="loadingbarSolution.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style x:Key="{x:Type ProgressBar}"
       TargetType="{x:Type ProgressBar}">

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ProgressBar">
                        <Border BorderBrush="#D9DCE1" BorderThickness="0" Background="#FF0C0B0B" CornerRadius="0" Padding="0">
                            <Grid x:Name="PART_Track">
                                <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#FF2BA9FF" />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>


        </Style>

    </Window.Resources>
        <Grid>
        <ProgressBar x:Name="IMSIProgressBar" 
                     HorizontalAlignment="Left" 
                     Height="20" Margin="82,136,0,0" 
                     VerticalAlignment="Top" 
                     Width="200" 
                     BorderThickness="1" Background="#FF0C0B0B"/>
    </Grid>
</Window>

我该怎么办?

【问题讨论】:

    标签: c# wpf xaml templates progress-bar


    【解决方案1】:

    返回代码:

    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>
    

    注意:如果高度是固定的,则不需要转换器,将边距设置为固定的厚度。转换器仅适用于自动调整大小。

    【讨论】:

    • 谢谢我有类似的东西,但我希望我可以让形状完全覆盖进度条,而不是在完成后留下一个小的三角形间隙
    • 好的,没关系。确实有点麻烦,但问题不大。
    【解决方案2】:

    您可以在模板中使用Polygon

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate 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,20 20,0 20,20" Stroke="#FF0C0B0B" Fill="#FF0C0B0B" HorizontalAlignment="Right" />
                        </Grid>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    

    无论何时Value == Maximum,您都必须隐藏它,例如使用转换器。

    【讨论】:

      【解决方案3】:

      第三种方法是使用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="&lt;Rectangle&gt; + &lt;SkewTansform&gt; (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="&lt;Polygon HorizontalAlignment=&quot;Right&quot; /&gt; (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="&lt;Path&gt; + &lt;SkewTransform&gt;" 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
      
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-01-19
        • 1970-01-01
        • 1970-01-01
        • 2015-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多