C# WPF 中沿轮廓带有进度条的矩形按钮

问题描述 投票:0回答:1

我需要在 C# 6.0 WPF 中创建一个带圆角的矩形按钮。该按钮应该有一个进度条,而不是一个顺时针填充的框架(从顶部边框的中间开始)。

我尝试了很多方法来做到这一点,甚至使用 Path 制作了一个稍微可行的版本,但没有我需要的圆角。

告诉我如何使用 xaml 标记来完成此操作以及如何管理进度。

这是一个带有圆角的常规按钮:

<UserControl x:Class="Example.ProgressButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Example"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button x:Name="button" Width="150" Height="60" Content="Click me" Background="LightGray" BorderBrush="Transparent">
            <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type Button}">
                                <Border CornerRadius="10" Background="{TemplateBinding Background}" BorderBrush="Green" BorderThickness="2">
                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</UserControl>

最初,框架不应该是可见的(无论有没有框架,按钮的大小都不应改变);单击时,进度条从上边框中间开始顺时针填充。填充 100% 后,按钮应如下图所示: button

此外,进度条的填充即使是圆角也应该平滑。

我根本不知道该怎么做。请帮助我。

c# wpf xaml progress-bar c#-6.0
1个回答
0
投票

它是几个问题的组合,包括:

我很快将一些东西打包在一起以帮助您开始。还有工作要做;)

Xaml:

<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800">
    <Window.Resources>

        <local:AngleToPointConverter x:Key="angleToPointConverter" />
        <local:AngleToIsLargeConverter x:Key="angleToIsLargeConverter" />

        <Style TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Viewbox Stretch="Fill"
                                     ClipToBounds="True">
                                <Viewbox.Clip>
                                    <RectangleGeometry RadiusX="10"
                                                       RadiusY="10"
                                                       Rect="0,0,200,100" />
                                </Viewbox.Clip>
                                <Path Stroke="LightGray"
                                      StrokeThickness="100"
                                      Width="100"
                                      Height="100">
                                    <Path.Data>
                                        <PathGeometry>
                                            <PathFigure StartPoint="50,0">
                                                <ArcSegment RotationAngle="0"
                                                            SweepDirection="Clockwise"
                                                            Size="50,50"
                                                            Point="{Binding DataContext.Angle, Converter={StaticResource angleToPointConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=Button}}"
                                                            IsLargeArc="{Binding DataContext.Angle, Converter={StaticResource angleToIsLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=Button}}">
                                                </ArcSegment>
                                            </PathFigure>
                                        </PathGeometry>
                                    </Path.Data>
                                </Path>
                            </Viewbox>
                            <Border CornerRadius="10"
                                    Background="Transparent"
                                    BorderBrush="Green"
                                    BorderThickness="2">
                                <ContentPresenter HorizontalAlignment="Center"
                                                  VerticalAlignment="Center" />
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <TextBlock Text="{Binding Progress}"
                   VerticalAlignment="Top" />
        <Button Width="200"
                Height="100"
                Content="Click me"
                Command="{Binding ClickCommand}" />
    </Grid>
</Window>

铯:

namespace WpfApp3
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public DelegateCommand ClickCommand { get; }

        public double Progress { get; set; }
        public double Angle => Progress / 100 * 360;

        public ViewModel()
        {
            var busy = false;

            ClickCommand = new(async o =>
            {
                busy = true;
                ClickCommand!.Update();

                for (int i = 1; i <= 100; i++)
                {
                    SetProgress(i);
                    await Task.Delay(20);
                }

                SetProgress(0);

                busy = false;
                ClickCommand.Update();

            }, o => !busy);
        }

        void SetProgress(double value)
        {
            Progress = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Progress)));
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Angle)));
        }
    }

    public class DelegateCommand : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        readonly Action<object?> execute;
        readonly Predicate<object?> canExecute;

        public DelegateCommand(Action<object?> execute, Predicate<object?> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public void Update() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

        public bool CanExecute(object? parameter) => canExecute(parameter);

        public void Execute(object? parameter) => execute(parameter);
    }

    class AngleToPointConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double angle = (double)value;
            double radius = 50;
            double piang = angle * Math.PI / 180;

            double px = Math.Sin(piang) * radius + radius;
            double py = -Math.Cos(piang) * radius + radius;

            return new Point(px, py);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    class AngleToIsLargeConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double angle = (double)value;

            return angle > 180;
        }

        public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.