C# 如何用半径和起止角绘制圆弧

C# 如何用半径和起止角绘制圆弧,c#,wpf,xaml,geometry,C#,Wpf,Xaml,Geometry,如果在画布元素的DataContext中有以下四个属性 Point Center double Radius double StartAngle double EndAngle 我可以在没有任何额外代码的情况下绘制圆弧吗?提供自定义组件是最好的解决方案。我在代码中这样使用它 <Controls:Arc Center="{Binding Path=PreviousMousePositionPixels}" Stroke="White" Stroke

如果在画布元素的DataContext中有以下四个属性

Point  Center
double Radius
double StartAngle
double EndAngle

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

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

<Controls:Arc Center="{Binding Path=PreviousMousePositionPixels}" 
         Stroke="White" 
         StrokeDashArray="4 4"
         SnapsToDevicePixels="True"
         StartAngle="0" 
         EndAngle="{Binding Path=DeltaAngle}" 
         SmallAngle="True"
         Radius="40" />

我可以提供一个稍微不同的解决方案吗

class ArcII:FrameworkElement
{
    /// <summary>
    /// Center point of Arc.
    /// </summary>
    [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));

    /// <summary>
    /// Forces the Arc to the center of the Parent container.
    /// </summary>
    [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));

    /// <summary>
    /// Start angle of arc, using standard coordinates. (Zero is right, CCW positive direction)
    /// </summary>
    [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));

    /// <summary>
    /// Length of Arc in degrees.
    /// </summary>
    [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));

    /// <summary>
    /// Size of Arc.
    /// </summary>
    [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<PathSegment> segments = new List<PathSegment>(1);
        segments.Add(new ArcSegment(endPoint, new Size(Radius, Radius), 0.0, isLarge, SweepDirection.Clockwise, true));

        List<PathFigure> figures = new List<PathFigure>(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);
    }
}
类别ArcII:框架元素
{
/// 
///弧的中心点。
/// 
[类别(“Arc”)]
公共点中心
{
获取{return(Point)GetValue(CenterProperty);}
set{SetValue(CenterProperty,value);}
}
//使用DependencyProperty作为Center的后台存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty CenterProperty=
DependencyProperty.Register(“中心”、typeof(点)、typeof(ArcII)、新FrameworkPropertyMetadata(新点(0,0)、FrameworkPropertyMetadata选项.AffectsRender));
/// 
///将圆弧强制到父容器的中心。
/// 
[类别(“Arc”)]
公共布尔覆盖中心
{
获取{return(bool)GetValue(OverrideCenterProperty);}
set{SetValue(OverrideCenterProperty,value);}
}
//使用DependencyProperty作为OverrideCenter的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性OverrideCenterProperty=
DependencyProperty.Register(“OverrideCenter”,typeof(bool),typeof(ArcII),new FrameworkPropertyMetadata((bool)false,FrameworkPropertyMetadata.AffectsRender));
/// 
///弧的起始角,使用标准坐标。(零为右,逆时针正方向)
/// 
[类别(“Arc”)]
公共双星纠缠
{
获取{return(double)GetValue(StartAngleProperty);}
set{SetValue(StartAngleProperty,value);}
}
//使用DependencyProperty作为StartAngle的后台存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性StartAngleProperty=
DependencyProperty.Register(“StartAngle”、typeof(double)、typeof(ArcII)、新的FrameworkPropertyMetadata(0.0,FrameworkPropertyMetadataOptions.AffectsRender));
/// 
///弧的长度(以度为单位)。
/// 
[类别(“Arc”)]
公共双扫掠角
{
获取{return(double)GetValue(sweepingproperty);}
set{SetValue(sweepingproperty,value);}
}
//使用DependencyProperty作为扫描角度的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性SweepAngleProperty=
DependencyProperty.Register(“扫掠角度”、typeof(double)、typeof(ArcII)、新FrameworkPropertyMetadata((double)180、FrameworkPropertyMetadata选项.AffectsRender));
/// 
///弧的大小。
/// 
[类别(“Arc”)]
公共双半径
{
获取{return(double)GetValue(radiuproperty);}
set{SetValue(radiuproperty,value);}
}
//使用DependencyProperty作为Radius的后台存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性RadiusProperty=
DependencyProperty.Register(“半径”、typeof(双精度)、typeof(ArcII)、新FrameworkPropertyMetadata(10.0,FrameworkPropertyMetadataOptions.AffectsRender));
[类别(“Arc”)]
公共画笔
{
获取{return(Brush)GetValue(StrokeProperty);}
set{SetValue(StrokeProperty,value);}
}
//使用DependencyProperty作为笔划的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性StrokeProperty=
DependencyProperty.Register(“Stroke”、typeof(Brush)、typeof(ArcII)、new FrameworkPropertyMetadata((Brush)Brush.Black、FrameworkPropertyMetadata Options.AffectsRender));
[类别(“Arc”)]
公共双冲程
{
获取{return(double)GetValue(StrokeThicknessProperty);}
set{SetValue(StrokeThicknessProperty,value);}
}
//使用DependencyProperty作为StrokeThickness的后台存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性StrokeThicknessProperty=
DependencyProperty.Register(“StrokeThickness”、typeof(double)、typeof(ArcII)、new FrameworkPropertyMetadata((double)1、FrameworkPropertyMetadata.AffectsRender));
受保护的覆盖无效OnRender(DrawingContext dc)
{
base.OnRender(dc);
抽签(dc);
}
专用作废绘图(DrawingContext dc)
{
点中心=新点();
如果(覆盖中心)
{
Rect Rect=新的Rect(renderize);
中心=极轴。中心点FROMRECT(rect);
}
其他的
{
中心=中心;
}
点startPoint=极坐标。极笛卡尔坐标(星形、半径、中心);
点端点=极坐标。极笛卡尔坐标(星形缠结+扫掠角、半径、中心);
尺寸=新尺寸(半径、半径);
布尔isLarge=(星形缠结+扫掠角)-星形缠结>180;
列表段=新列表(1);
添加(新圆弧段(端点,新尺寸(半径,半径),0.0,isLarge,SweepDirection.顺时针,true));
列表数字=新列表(1);
PathFigure pf=新的路径图(起点、分段、真);
pf.IsClosed=false;
图.添加(pf);
几何图形g=新的路径几何图形(figures,FillRule.EvenOdd,null);
DrawGeometry(空,新笔(笔划,笔划厚度),g);
}
}
用法:

    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="100"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="95"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="90"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Point-->
    <local:ArcII Center="0,150"
                 OverrideCenter="False"
                 StartAngle="270"
                 SweepAngle="180"
                 Radius="100"
                 />

    <!--Centerd on Point-->
    <local:ArcII Center="525,150"
                 OverrideCenter="False"
                 StartAngle="90"
                 SweepAngle="180"
                 Radius="100"
                 />

注: A) 这不会产生360度扫掠角,因为它使用椭圆。 B) OverrideCenter:将圆弧的中心置于其父圆弧的中心。请注意,可以分区的网格等元素仍有一个中心,该中心可能不是弧所在的列或行。

可能几乎有用,但
    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="100"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="95"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Parent-->
    <local:ArcII Center="0,0"
                 OverrideCenter="True"
                 StartAngle="150"
                 SweepAngle="240"
                 Radius="90"
                 Stroke="Red"
                 StrokeThickness="3"
                 />

    <!--Centerd on Point-->
    <local:ArcII Center="0,150"
                 OverrideCenter="False"
                 StartAngle="270"
                 SweepAngle="180"
                 Radius="100"
                 />

    <!--Centerd on Point-->
    <local:ArcII Center="525,150"
                 OverrideCenter="False"
                 StartAngle="90"
                 SweepAngle="180"
                 Radius="100"
                 />