簡體   English   中英

如何在 wpf 中制作自定義形狀的進度條?

[英]How do I make a custom shape of progressbar in wpf?

好的,我將在 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>

我該怎么辦?

返回代碼:

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>

注意:如果高度是固定的,則不需要轉換器,將邊距設置為固定的厚度。 轉換器僅適用於自動調整大小。

您可以在模板中使用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時隱藏它,例如使用轉換器。

在此處輸入圖片說明

第三種方法是使用PathSkewTransform 這樣,移動指標確實完全達到 100 %。 2018 年的兩種方法與此方法的比較:

帶有傾斜指示器的進度條

以上 APNG 的完整代碼:
主窗口.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 不是必需的):
主窗口.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

        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM