如何绘制半径弧和起始和停止角度

如果我的Canvas元素的DataContext中有以下四个属性

Point Center double Radius double StartAngle double EndAngle 

我可以在没有任何额外代码的情况下绘制弧线吗?

提供自定义组件是最佳解决方案。 我在我的代码中使用它

  

SmallAngle true将呈现点之间的小角度,而与StartAngleEndAngle的顺序EndAngle 。 当SmallAnglefalse ,弧逆时针呈现。

实施是

 using System; using System.Collections.Generic; using System.Windows; using System.Windows.Media; using System.Windows.Shapes; public sealed class Arc : Shape { public Point Center { get => (Point)GetValue(CenterProperty); set => SetValue(CenterProperty, value); } // Using a DependencyProperty as the backing store for Center. This enables animation, styling, binding, etc... public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(nameof(Center), typeof(Point), typeof(Arc), new FrameworkPropertyMetadata(new Point(), FrameworkPropertyMetadataOptions.AffectsRender)); public double StartAngle { get => (double)GetValue(StartAngleProperty); set => SetValue(StartAngleProperty, value); } // Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register(nameof(StartAngle), typeof(double), typeof(Arc), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)); public double EndAngle { get => (double)GetValue(EndAngleProperty); set => SetValue(EndAngleProperty, value); } // Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty EndAngleProperty = DependencyProperty.Register(nameof(EndAngle), typeof(double), typeof(Arc), new FrameworkPropertyMetadata(Math.PI / 2.0, FrameworkPropertyMetadataOptions.AffectsRender)); public double Radius { get => (double)GetValue(RadiusProperty); set => SetValue(RadiusProperty, value); } // Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc... public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register(nameof(Radius), typeof(double), typeof(Arc), new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender)); public bool SmallAngle { get => (bool)GetValue(SmallAngleProperty); set => SetValue(SmallAngleProperty, value); } // Using a DependencyProperty as the backing store for SmallAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty SmallAngleProperty = DependencyProperty.Register(nameof(SmallAngle), typeof(bool), typeof(Arc), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)); static Arc() => DefaultStyleKeyProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(typeof(Arc))); protected override Geometry DefiningGeometry { get { double a0 = StartAngle < 0 ? StartAngle + 2 * Math.PI : StartAngle; double a1 = EndAngle < 0 ? EndAngle + 2 * Math.PI : EndAngle; if (a1 < a0) a1 += Math.PI * 2; SweepDirection d = SweepDirection.Counterclockwise; bool large; if (SmallAngle) { large = false; d = (a1 - a0) > Math.PI ? SweepDirection.Counterclockwise : SweepDirection.Clockwise; } else large = (Math.Abs(a1 - a0) < Math.PI); Point p0 = Center + new Vector(Math.Cos(a0), Math.Sin(a0)) * Radius; Point p1 = Center + new Vector(Math.Cos(a1), Math.Sin(a1)) * Radius; List segments = new List { new ArcSegment(p1, new Size(Radius, Radius), 0.0, large, d, true) }; List figures = new List { new PathFigure(p0, segments, true) { IsClosed = false } }; return new PathGeometry(figures, FillRule.EvenOdd, null); } } } 

我可以提供略有不同的解决方案吗?

 class ArcII:FrameworkElement { ///  /// Center point of Arc. ///  [Category("Arc")] public Point Center { get { return (Point)GetValue(CenterProperty); } set { SetValue(CenterProperty, value); } } // Using a DependencyProperty as the backing store for Center. This enables animation, styling, binding, etc... public static readonly DependencyProperty CenterProperty = DependencyProperty.Register("Center", typeof(Point), typeof(ArcII), new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender)); ///  /// Forces the Arc to the center of the Parent container. ///  [Category("Arc")] public bool OverrideCenter { get { return (bool)GetValue(OverrideCenterProperty); } set { SetValue(OverrideCenterProperty, value); } } // Using a DependencyProperty as the backing store for OverrideCenter. This enables animation, styling, binding, etc... public static readonly DependencyProperty OverrideCenterProperty = DependencyProperty.Register("OverrideCenter", typeof(bool), typeof(ArcII), new FrameworkPropertyMetadata((bool)false, FrameworkPropertyMetadataOptions.AffectsRender)); ///  /// Start angle of arc, using standard coordinates. (Zero is right, CCW positive direction) ///  [Category("Arc")] public double StartAngle { get { return (double)GetValue(StartAngleProperty); } set { SetValue(StartAngleProperty, value); } } // Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register("StartAngle", typeof(double), typeof(ArcII), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)); ///  /// Length of Arc in degrees. ///  [Category("Arc")] public double SweepAngle { get { return (double)GetValue(SweepAngleProperty); } set { SetValue(SweepAngleProperty, value); } } // Using a DependencyProperty as the backing store for SweepAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty SweepAngleProperty = DependencyProperty.Register("SweepAngle", typeof(double), typeof(ArcII), new FrameworkPropertyMetadata((double)180, FrameworkPropertyMetadataOptions.AffectsRender)); ///  /// Size of Arc. ///  [Category("Arc")] public double Radius { get { return (double)GetValue(RadiusProperty); } set { SetValue(RadiusProperty, value); } } // Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc... public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(ArcII), new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender)); [Category("Arc")] public Brush Stroke { get { return (Brush)GetValue(StrokeProperty); } set { SetValue(StrokeProperty, value); } } // Using a DependencyProperty as the backing store for Stroke. This enables animation, styling, binding, etc... public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register("Stroke", typeof(Brush), typeof(ArcII), new FrameworkPropertyMetadata((Brush)Brushes.Black,FrameworkPropertyMetadataOptions.AffectsRender)); [Category("Arc")] public double StrokeThickness { get { return (double)GetValue(StrokeThicknessProperty); } set { SetValue(StrokeThicknessProperty, value); } } // Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc... public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(double), typeof(ArcII), new FrameworkPropertyMetadata((double)1,FrameworkPropertyMetadataOptions.AffectsRender)); protected override void OnRender(DrawingContext dc) { base.OnRender(dc); Draw(dc); } private void Draw(DrawingContext dc) { Point center = new Point(); if (OverrideCenter) { Rect rect = new Rect(RenderSize); center = Polar.CenterPointFromRect(rect); } else { center = Center; } Point startPoint = Polar.PolarToCartesian(StartAngle, Radius, center); Point endPoint = Polar.PolarToCartesian(StartAngle + SweepAngle, Radius, center); Size size = new Size(Radius, Radius); bool isLarge = (StartAngle + SweepAngle) - StartAngle > 180; List segments = new List(1); segments.Add(new ArcSegment(endPoint, new Size(Radius, Radius), 0.0, isLarge, SweepDirection.Clockwise, true)); List figures = new List(1); PathFigure pf = new PathFigure(startPoint, segments, true); pf.IsClosed = false; figures.Add(pf); Geometry g = new PathGeometry(figures, FillRule.EvenOdd, null); dc.DrawGeometry(null, new Pen(Stroke,StrokeThickness), g); } } 

用法:

            

注意:A)这不会使用360 SweepAngle,因为使用椭圆。 B)OverrideCenter:这将Arc的中心放在其父级的中心。 请注意,像Grid这样可以分区的元素仍然有一个中心,它可能不是Arc所在的列或行。