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

C# 从形状派生的WPF自定义形状类,c#,wpf,xaml,shape,C#,Wpf,Xaml,Shape,我正试图在WPF中创建一个自定义的楔形形状类,它派生自抽象形状类,并且能够像其他形状一样在XAML中定义它 我一直在谷歌上搜索关于如何实现这一点的完整教程,但我找到的都是关于自定义控件的内容。我想要的是创建一个楔子类,它允许我指定内半径、外半径、该楔子在360度范围内的截面数(即,如果我想在圆周围安装24个楔子,则该楔子的大小将与24个楔子的大小相同)及其位置(它将占据24个空间中的哪一个)。这些都是依赖属性,我已经注册了它们 DefiningGeometry属性调用一个方法,该方法执行计算点和

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

我一直在谷歌上搜索关于如何实现这一点的完整教程,但我找到的都是关于自定义控件的内容。我想要的是创建一个楔子类,它允许我指定内半径、外半径、该楔子在360度范围内的截面数(即,如果我想在圆周围安装24个楔子,则该楔子的大小将与24个楔子的大小相同)及其位置(它将占据24个空间中的哪一个)。这些都是依赖属性,我已经注册了它们

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

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

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

如果我把它注释掉,所有的东西都会编译,但是楔形块没有显示在表单上。如何实现此模板设置器属性?我需要吗

XAML:


我刚刚在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" />

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

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;
    }
}

形状不是
控件
,因此您将没有它的
模板
属性。您可能没有设置
填充
,或
笔划
属性?Post XAML以便向我们展示您如何尝试在屏幕上显示楔块。您是否也可以发布
定义几何体
?受保护的覆盖几何体定义几何体{get{使用(StreamGeometryContext context=Geometry.Open(){DrawWedgeGeometry(context);}返回几何体;}@ourmanflint请编辑您的问题,使其包含此代码并正确格式化,而不是将其作为注释发布。还请包含完整代码和XAML。顺便说一句,如果您在谷歌上搜索“支持数据绑定的WPF饼图”,则该项目包含一个名为“Piepeat”的形状类,它似乎完全符合您的要求。
<local:Wedge Radius="50" Stroke="Black" Fill="Yellow" StrokeThickness="2" Canvas.Top="100" Canvas.Left="100" />
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;
    }
}