从形状派生的WPF自定义形状类

时间:2013-11-26 17:46:44

标签: c# wpf xaml shape

我试图在WPF中创建一个自定义的wedge形状类,派生自抽象的Shape类,并且能够像在任何其他形状中一样在XAML中定义它。

我一直在Google上搜索有关如何执行此操作的完整教程,但我发现的只是自定义控件的内容。我想要的是创建一个楔形类,允许我指定内半径,外半径,这个楔形将成为360度中的多少部分(即,如果我想在圆周围安装这些楔子中的24个,这个wedge将是正确的大小,以及它的位置(它将占据的24个空间中的一个)。这些都是依赖属性,我已经注册了它们。

DefiningGeometry属性调用一个方法,该方法执行计算点和绘制形状的所有逻辑。

我遇到的问题是VS2010使用属性“模板”的设置器自动创建了一个样式。然后,当我编译时,它给我一个错误说:

“错误3无法在类型'WpfApplication1.Wedge'上找到样式属性'模板'。第8行位置17. C:\ Users \ rflint \ Desktop \ WpfApplication1 \ WpfApplication1 \ Themes \ Generic.xaml 8 17 WpfApplication1”

如果我对此进行评论,则所有内容都会编译,但楔形不会显示在表单上。如何实现此模板设置器属性?我需要吗?

XAML:

    <my:Wedge CenterPoint="300,300" InnerRadius="100" OuterRadius="200" Sections="12" Position="0" Stroke="Transparent" Fill="#FFCC7329" />

C#:

protected override Geometry DefiningGeometry
{
  get
  {
    using (StreamGeometryContext context = geometry.Open())
    {
      DrawWedgeGeometry(context);
    }

    return geometry;
  }
}

        private void DrawWedgeGeometry(StreamGeometryContext context)
    {
        double wedgeAngle = 360/Sections;
        double angleA = (Position * wedgeAngle) + (wedgeAngle/2);
        double angleB = (Position * wedgeAngle) - (wedgeAngle/2);
        Point point1 = getPointOnCircle(CenterPoint, InnerRadius, angleA);
        Point point2 = getPointOnCircle(CenterPoint, InnerRadius, angleB);
        Point point3 = getPointOnCircle(CenterPoint, OuterRadius, angleB);
        Point point4 = getPointOnCircle(CenterPoint, OuterRadius, angleA);

        Size innerSize = new Size(InnerRadius, InnerRadius);
        Size outerSize = new Size(OuterRadius, OuterRadius);

        context.BeginFigure(point1, true, true);
        context.ArcTo(point2, innerSize, 90, false, SweepDirection.Clockwise, true, true);
        context.LineTo(point3, true, true);
        context.ArcTo(point4, outerSize, 90, false, SweepDirection.Counterclockwise, true, true);
    }

2 个答案:

答案 0 :(得分:2)

我刚刚在VS2012上试过它并且工作正常,至少是一个简单的椭圆几何:

public sealed class Wedge : Shape
{
    public Double Radius
    {
        get { return (Double)this.GetValue(RadiusProperty); }
        set { this.SetValue(RadiusProperty, value); }
    }
    public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register(
      "Radius", typeof(Double), typeof(Wedge), new PropertyMetadata(0.0));

    protected override Geometry DefiningGeometry
    {
        get {return new EllipseGeometry(new Point(0, 0), this.Radius, this.Radius); }
    }
}

和XAML:

<local:Wedge Radius="50" Stroke="Black" Fill="Yellow" StrokeThickness="2" Canvas.Top="100" Canvas.Left="100" />

答案 1 :(得分:0)

让我为您的问题提供一个简单的解决方案:

public class Wedge : Shape
{
    public Double StartAngle
    {
        get { return (Double)GetValue(StartAngleProperty); }
        set { SetValue(StartAngleProperty, value); }
    }

    public static readonly DependencyProperty StartAngleProperty =
        DependencyProperty.Register("StartAngle", typeof(Double), typeof(Wedge), new PropertyMetadata(0d));


    public Double EndAngle
    {
        get { return (Double)GetValue(EndAngleProperty); }
        set { SetValue(EndAngleProperty, value); }
    }

    public static readonly DependencyProperty EndAngleProperty =
        DependencyProperty.Register("EndAngle", typeof(Double), typeof(Wedge), new PropertyMetadata(0d));


    public Point Center
    {
        get { return (Point)GetValue(CenterProperty); }
        set { SetValue(CenterProperty, value); }
    }

    public static readonly DependencyProperty CenterProperty =
        DependencyProperty.Register("Center", typeof(Point), typeof(Wedge), new PropertyMetadata(new Point()));



    public Double InnerRadius
    {
        get { return (Double)GetValue(InnerRadiusProperty); }
        set { SetValue(InnerRadiusProperty, value); }
    }

    public static readonly DependencyProperty InnerRadiusProperty =
        DependencyProperty.Register("InnerRadius", typeof(Double), typeof(Wedge), new PropertyMetadata(0d));

    public Double OuterRadius
    {
        get { return (Double)GetValue(OuterRadiusProperty); }
        set { SetValue(OuterRadiusProperty, value); }
    }

    public static readonly DependencyProperty OuterRadiusProperty =
        DependencyProperty.Register("OuterRadius", typeof(Double), typeof(Wedge), new PropertyMetadata(0d));

    protected override Geometry DefiningGeometry
    {
        get
        {
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext context = geometry.Open())
            {
                Draw(context);
            }
            return geometry;
        }
    }

    private void Draw(StreamGeometryContext context)
    {
        var isStroked = Stroke != null & Stroke != Brushes.Transparent & StrokeThickness > 0;
        var isFilled = Fill != null & Fill != Brushes.Transparent;

        context.BeginFigure(
            GetPointOnCircle(Center, OuterRadius, StartAngle),
            isFilled, 
            true);

        context.ArcTo(
            GetPointOnCircle(Center, OuterRadius, EndAngle), 
            new Size(OuterRadius, OuterRadius),
            0,
            EndAngle - StartAngle > 180, 
            SweepDirection.Clockwise,
            isStroked, 
            true);

        context.LineTo(GetPointOnCircle(Center, InnerRadius, EndAngle), isStroked, true);

        context.ArcTo(
            GetPointOnCircle(Center, InnerRadius, StartAngle),
            new Size(InnerRadius, InnerRadius),
            0,
            EndAngle - StartAngle > 180,
            SweepDirection.Counterclockwise,
            isStroked,
            true);

        context.LineTo(GetPointOnCircle(Center, OuterRadius, StartAngle), isStroked, true);
    }

    private Point GetPointOnCircle(Point center, double radius, double angle)
    {
        var px = center.X + radius * Math.Cos(ToRadians(angle));
        var py = center.Y + radius * Math.Sin(ToRadians(angle));
        return new Point(px, py);
    }

    public double ToRadians(double angle)
    {
        return angle * Math.PI / 180;
    }
}