如何使用 C# 和 WPF 为圆形进度条创建选框并仅填充进度条的灰色区域

How to create a Marquee for Circular Progress Bar and fill only the gray area of bar using C# and WPF

提问人:WDpad159 提问时间:11/5/2023 最后编辑:WDpad159 更新时间:11/8/2023 访问量:102

问:

我创建了一个自定义的圆形进度条,如下所示:

enter image description here

使用以下代码:

<UserControl x:Class="WpfApp1.SpinnerProgressBar"
             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:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
            <Viewbox>
            <Canvas Width="100" Height="100">
                <!-- Base Spinner -->
            <Path Stroke="LightGray" StrokeThickness="3" Fill="LightGray"
                      Data="M 0 100 a 100,100 0 1 1 200,0 
                                    a 100,100 0 1 1 -200,0 
                            M 30 100 a 70,70 0 1 1 140,0
                                     a 70,70 0 1 1 -140,0" RenderTransformOrigin="0.5,0.5" />

            <!-- Loader Spinner "M 0 100 a 100,100 0 0 1 100,-100 v 30 a 70,70 0 0 0 -70,70" -->

            <Path Fill="Gold" Data="M 0 100 a 100,100 0 0 1 100,-100 v 30 
                                              a 70,70 0 0 0 -70,70" RenderTransformOrigin="1,1" >
                <Path.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform Angle="0"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Path.RenderTransform>
            </Path>
        </Canvas>
    </Viewbox>

</UserControl>

通过模仿跑马灯行为,我只需要绑定到(如果我没记错的话)。但是,当有成功连接到数据库的情况以及仍在尝试连接时使用选框时,我被困在如何创建完整的进度条上。我怎样才能完成完整的进度条部分?如果有教程/视频可以解释如何做到这一点,我将不胜感激。<RotateTransform Angle="0"/>

编辑1:多亏了@EldHasp我做了以下操作,我尝试了以下代码:

SpinnerProgressBar.xaml

<UserControl x:Class="SpinnerProgress.SpinnerProgressBar"
             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:SpinnerProgress"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             xmlns:rpb="clr-namespace:SpinnerProgress.spinnerprogressbar">

    <!-- Spinner Design -->
        <!-- Use the text document about the path commands in Data. -->
        <Viewbox>
            <Grid>
                <!-- Arc Movement requirements: (Size, (RotatingAngle, isLargeArc, SweepDirection), Coordinates[End-points]) -->
                <Canvas Width="100" Height="100">
                    <Path Stroke="LightGray" StrokeThickness="3" Fill="LightGray" Panel.ZIndex="2"
                          Data="M 0 100 a 100,100 0 1 1 200,0 
                                        a 100,100 0 1 1 -200,0 
                                M 30 100 a 70,70 0 1 1 140,0
                                         a 70,70 0 1 1 -140,0" RenderTransformOrigin="0.5,0.5" />
                    <!-- Arc Movement requirements: (Size, (RotatingAngle, isLargeArc, SweepDirection), Coordinates[End-points]) -->
                    <!-- Loader Spinner "M 0 100 a 100,100 0 0 1 100,-100 v 30 a 70,70 0 0 0 -70,70" -->
                    <Path x:Name="progressPath" Fill="Gold" RenderTransformOrigin="1,1">
                        <Path.Data>
                        <MultiBinding Converter="{x:Static local:ProgressBarToGeometryConverter.Instance}">
                                <Binding Path="Value" RelativeSource="{RelativeSource AncestorType=local:SpinnerProgressBar}"/>
                                <Binding Path="Maximum" RelativeSource="{RelativeSource AncestorType=local:SpinnerProgressBar}"/>
                                <Binding Path="Minimum" RelativeSource="{RelativeSource AncestorType=local:SpinnerProgressBar}"/>
                            </MultiBinding>
                        </Path.Data>
                    </Path>
                </Canvas>
            </Grid>
        </Viewbox>
    
</UserControl>

SpinnerProgressBar 背后的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SpinnerProgress
{
    /// <summary>
    /// Interaction logic for SpinnerProgressBar.xaml
    /// </summary>
    public partial class SpinnerProgressBar : UserControl
    {
        public SpinnerProgressBar()
        {
            InitializeComponent();
        }

        private void StartMarqueeAnimation()
        {
            // Create a double animation to rotate the Path (marquee effect)
            var rotationAnimation = new DoubleAnimation
            {
                To = 360, // Rotate a full circle (360 degrees)
                Duration = TimeSpan.FromSeconds(1), // Adjust the duration as needed
                RepeatBehavior = RepeatBehavior.Forever // Keep repeating the animation
            };

            progressPath.RenderTransform = new RotateTransform(); // Add a RotateTransform
            progressPath.RenderTransformOrigin = new Point(1, 1); // Set the rotation origin to the center

            // Begin the rotation animation
            progressPath.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, rotationAnimation);
        }
    }
}

MainWindow.xaml

<Window x:Class="SpinnerProgress.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:SpinnerProgress"
        xmlns:spb="clr-namespace:SpinnerProgress.spinnerprogressbar"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Duration="0:0:5"
                                     To="10"
                                     Storyboard.TargetName="Spinner"
                                     Storyboard.TargetProperty="Value"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>

    <Grid>
        <spb:SpinnerProgressBar x:Name="Spinner" Maximum="10" Minimum="-10" Value="-10" Height="100" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
    
</Window>

转换器.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;
using static System.Math;

namespace SpinnerProgress.spinnerprogressbar
{
    public class SpinnerProgressBar : RangeBase
    {
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(SpinnerProgressBar), new PropertyMetadata(0.0));
        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(SpinnerProgressBar), new PropertyMetadata(0.0));
        public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(SpinnerProgressBar), new PropertyMetadata(0.0));

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        static SpinnerProgressBar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SpinnerProgressBar), new FrameworkPropertyMetadata(typeof(SpinnerProgressBar)));
        }
    }

    [ValueConversion(typeof(SpinnerProgressBar), typeof(Geometry))]
    public class ProgressBarToGeometryConverter : IMultiValueConverter
    {
        private static readonly double valPI = 2 * PI;
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            double min = (double)values[0];
            double max = (double)values[1];
            double value = (double)values[2];

            double angle = (value - min) / (max - min);
            angle *= valPI;
            if (!double.IsNormal(angle))
                return DependencyProperty.UnsetValue;

            double cos = Cos(angle);
            double sin = Sin(angle);
            double x1 = 100 * cos + 100;
            double y1 = 100 * sin + 100;
            double x2 = 70 * cos + 100;
            double y2 = 70 * sin + 100;

            StreamGeometry sg = new();
            sg.FillRule = FillRule.EvenOdd;

            using StreamGeometryContext sgc = sg.Open();
            if (value >= max)
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(0, 100), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.ArcTo(new Point(200, 100), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(170, 100), true, false);
                sgc.ArcTo(new Point(30, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
            }
            else
            if (angle < PI)
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(x1, y1), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(x2, y2), true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
            }
            else
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(x1, y1), new Size(100, 100), 0, true, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(x2, y2), true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, true, SweepDirection.Counterclockwise, true, false);
            }
            return sg;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public ProgressBarToGeometryConverter() { }
        public static ProgressBarToGeometryConverter Instance { get; } = new();
    }

    [MarkupExtensionReturnType(typeof(ProgressBarToGeometryConverter))]
    public class ProgressBarToGeometryExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return ProgressBarToGeometryConverter.Instance;
        }
    }
}

它似乎不起作用。我正在考虑将选框添加到代码中。

C# WPF XAML 进度条

评论


答:

1赞 MIHOW 11/5/2023 #1

为选框效果制作旋转动画非常简单,只需对属性进行动画处理即可。RenderTransform.RotateTranform

你可以像这样实现它。这是 的声明,对旋转有一些额外的效果,以及 on selected 的触发示例。StoryboardIsMouseOverPath

<UserControl.Resources>
    <Storyboard x:Key="SpinStoryboardSpinning" RepeatBehavior="Forever">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)">
            <EasingDoubleKeyFrame KeyTime="0:0:0" Value="90"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="180"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="450">
                <EasingDoubleKeyFrame.EasingFunction>
                    <QuadraticEase EasingMode="EaseInOut"/>
                </EasingDoubleKeyFrame.EasingFunction>
            </EasingDoubleKeyFrame>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</UserControl.Resources>

<Path Fill="Gold"
      Data="M 0 100 a 100,100 0 0 1 100,-100 v 30 a 70,70 0 0 0 -70,70"
      RenderTransformOrigin="1,1">
    <Path.RenderTransform>
            <RotateTransform Angle="90"/>
    </Path.RenderTransform>
    <Path.Style>
        <Style TargetType="{x:Type Path}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource SpinStoryboardSpinning}"/>
                    </Trigger.EnterActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Path.Style>
</Path>

但是为了创建一个完整的进度条,这是一项更复杂的任务。

首先,您需要控制创建的,即在需要时停止和启动它们。同样对于它本身,我建议从控件派生开始,并根据需要设置其样式。StoryboardsProgressBarProgressBar

好的开始是首先创建标准,但样式基于 MSDN https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/progressbar-styles-and-templates?view=netframeworkdesktop-4.8 中的此示例ProgressBar

评论

0赞 WDpad159 11/5/2023
感谢您的及时回复。我将看一下动画,但它也可以通过 Marquee 行为的背后代码来完成吗?关于填充条形图,您的意思是开始和停止,例如从选框更改为填充路径?我会看看你发送的链接
0赞 MIHOW 11/5/2023
我将按照我发布的示例中的描述使用 VisualStates,并在 Intermediate State 上显示 Marquee,而在 Dedetermined 上显示实际进度。关于故事板,这是一篇好文章 learn.microsoft.com/en-us/dotnet/desktop/wpf/...
1赞 WDpad159 11/7/2023
谢谢,该代码适用于选框。我将阅读有关故事板的信息,并了解如何将其实现到进度条中。
1赞 EldHasp 11/6/2023 #2

圆形 ProgressBar 的示例。

自定义控制和转换器:

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;
using static System.Math;

namespace Core2023.RoundProgressBar
{
    public class RoundProgressBar : RangeBase
    {
        static RoundProgressBar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RoundProgressBar), new FrameworkPropertyMetadata(typeof(RoundProgressBar)));
        }
    }

    [ValueConversion(typeof(ProgressBar), typeof(Geometry))]
    public class ProgressBarToGeometryConverter : IMultiValueConverter
    {
        private static readonly double valPI = 2 * PI;
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            double min = (double)values[0];
            double max = (double)values[1];
            double value = (double)values[2];

            double angle = (value - min) / (max - min);
            angle *= valPI;
            if (!double.IsNormal(angle))
                return DependencyProperty.UnsetValue;

            double cos = Cos(angle);
            double sin = Sin(angle);
            double x1 = 100 * cos + 100;
            double y1 = 100 * sin + 100;
            double x2 = 70 * cos + 100;
            double y2 = 70 * sin + 100;


            string data;
            if (angle < PI)
            {
                data = @$"
M200,100
A100,100 0 0 1 {x1.ToString(culture)},{y1.ToString(culture)}
L{x2.ToString(culture)},{y2.ToString(culture)}
A070,070 0 0 0 170,100
z";
            }
            else
            {
                data = @$"
M200,100
A100,100 0 1 1 {x1.ToString(culture)},{y1.ToString(culture)}
L{x2.ToString(culture)},{y2.ToString(culture)}
A070,070 0 1 0 170,100
z";
            }
            return Geometry.Parse(data);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        private ProgressBarToGeometryConverter() { }
        public static ProgressBarToGeometryConverter Instance { get; } = new();
    }

    [MarkupExtensionReturnType(typeof(ProgressBarToGeometryConverter))]
    public class ProgressBarToGeometryExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return  ProgressBarToGeometryConverter.Instance;
        }
    }
}

主题 Generic.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Core2023"
    xmlns:rpb="clr-namespace:Core2023.RoundProgressBar">


    <Style TargetType="{x:Type rpb:RoundProgressBar}">
        <Setter Property="Background" Value="LightGray"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type rpb:RoundProgressBar}">
                    <ControlTemplate.Resources>
                        <Geometry x:Key="round">
                            M 0 100 a 100,100 0 1 1 200,0
                            a 100,100 0 1 1 -200,0
                            M 30 100 a 70,70 0 1 1 140,0
                            a 70,70 0 1 1 -140,0</Geometry>
                    </ControlTemplate.Resources>
                    <Grid>
                        <!-- Base Spinner -->
                        <Path Fill="{TemplateBinding Background}"
                              Data="{StaticResource round}"/>
                        <Path Stroke="{TemplateBinding BorderBrush}" StrokeThickness="3"
                              Data="{StaticResource round}" Panel.ZIndex="2"/>

                        <!-- Loader Spinner "M 0 100 a 100,100 0 0 1 100,-100 v 30 a 70,70 0 0 0 -70,70" -->

                        <Path Fill="Gold">
                            <Path.Data>
                                <MultiBinding Converter="{rpb:ProgressBarToGeometry}">
                                    <Binding RelativeSource="{RelativeSource AncestorType=rpb:RoundProgressBar}" Path="Minimum"/>
                                    <Binding RelativeSource="{RelativeSource AncestorType=rpb:RoundProgressBar}" Path="Maximum"/>
                                    <Binding RelativeSource="{RelativeSource AncestorType=rpb:RoundProgressBar}" Path="Value"/>
                                </MultiBinding>
                            </Path.Data>
                        </Path>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

带有 Value 属性的使用和动画示例的窗口:

<Window x:Class="Core2023.RoundProgressBar.RoundProgressBarWindow"
        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:Core2023.RoundProgressBar"
        mc:Ignorable="d"
        Title="RoundProgressBarWindow" Height="450" Width="800">
    <Window.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Duration="0:0:5"
                                     To="10"
                                     Storyboard.TargetName="rpb"
                                     Storyboard.TargetProperty="Value"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <local:RoundProgressBar x:Name="rpb"
                                Maximum="10" Minimum="-10" Value="-10"
                                BorderBrush="Aqua"/>
    </Grid>
</Window>

Value 属性可以绑定到 ViewModel,也可以以任何其他方式进行设置。进度将正确显示。

附言这是使用 StreamGeometry 的转换器的改进版本。

    [ValueConversion(typeof(ProgressBar), typeof(Geometry))]
    public class ProgressBarToGeometryConverter : IMultiValueConverter
    {
        private static readonly double valPI = 2 * PI;
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            double min = (double)values[0];
            double max = (double)values[1];
            double value = (double)values[2];

            double angle = (value - min) / (max - min);
            angle *= valPI;
            if (!double.IsNormal(angle))
                return DependencyProperty.UnsetValue;

            double cos = Cos(angle);
            double sin = Sin(angle);
            double x1 = 100 * cos + 100;
            double y1 = 100 * sin + 100;
            double x2 = 70 * cos + 100;
            double y2 = 70 * sin + 100;

            StreamGeometry sg = new();
            sg.FillRule = FillRule.EvenOdd;

            using StreamGeometryContext sgc = sg.Open();
            if (value >= max)
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(0, 100), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.ArcTo(new Point(200, 100), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(170, 100), true, false);
                sgc.ArcTo(new Point(30, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
            }
            else
            if (angle < PI)
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(x1, y1), new Size(100, 100), 0, false, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(x2, y2), true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, false, SweepDirection.Counterclockwise, true, false);
            }
            else
            {
                sgc.BeginFigure(new Point(200, 100), true, true);
                sgc.ArcTo(new Point(x1, y1), new Size(100, 100), 0, true, SweepDirection.Clockwise, true, false);
                sgc.LineTo(new Point(x2, y2), true, false);
                sgc.ArcTo(new Point(170, 100), new Size(070, 070), 0, true, SweepDirection.Counterclockwise, true, false);
            }
            return sg;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        private ProgressBarToGeometryConverter() { }
        public static ProgressBarToGeometryConverter Instance { get; } = new();
    }

“编辑 1”中的错误

  1. “class SpinnerProgressBar : UserControl” - 这个类是多余的。删除它。
  2. 在类“class SpinnerProgressBar : RangeBase”中,无需声明 Minimum、Maxmimum 和 Value 属性。这些属性已在基类“RangeBase”中声明。
  3. 类“SpinnerProgressBar : RangeBase”是一个自定义控件,您需要为其声明一个主题。默认主题是文件“Themes/Generic.xaml”。

您可以从此处下载完整的工作项目:https://drive.google.com/file/d/1lUpKDHz0QQ_NoFEXeXeWBcBMVgj8WZhW/view?usp=drive_link

评论

0赞 Clemens 11/6/2023
转换器代码看起来很奇怪。当您可以直接创建 PathGeometry 或 StreamGeometry 时,为什么要从字符串解析 Geometry?为什么它应该是一个 MarkupExtension(没有任何解释),因为它可以简单地声明为内联或作为 XAML 资源?
0赞 EldHasp 11/6/2023
@Clemens,该示例是“匆忙”创建的,使用字符串可以更容易、更快速地调试代码。我同意你的看法,可以更优化地做到这一点。在这种情况下,我认为最好的方法是使用 StreamGeometry。
0赞 Clemens 11/6/2023
“匆忙”——好吧,解决这个问题,让它成为一个好的答案。没有什么比匆忙写出让坏代码生存的答案更糟糕的了。想象一下,一个新手看到这一点,并得到的印象是这是创建几何图形的方法。
0赞 EldHasp 11/6/2023
@Clemens,我已经更新了我的答案以考虑您的评论。
1赞 EldHasp 11/8/2023
@WDpad159 阅读我的答案的更新。