【问题标题】:WPF Custom Shape Class Derived from Shape派生自 Shape 的 WPF 自定义 Shape 类
【发布时间】:2013-11-26 17:46:43
【问题描述】:

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

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

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

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

“错误 3 在类型 'WpfApplication1.Wedge' 上找不到样式属性 'Template'。第 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);
    }

【问题讨论】:

  • Shape 不是Control,因此您将没有Template 属性。您可能没有设置FillStroke 属性?发布 XAML,向我们展示您如何尝试在屏幕上显示 Wedge。
  • 你也可以发DefiningGeometry吗?
  • protected override Geometry DefiningGeometry { get { using (StreamGeometryContext context = geometry.Open()) { DrawWedgeGeometry(context); } 返回几何; }
  • @ourmanflint 请编辑您的问题以包含此代码并正确格式化,而不是将其发布为 cmets。另请附上您的完整代码和 XAML。

标签: c# wpf xaml shape


【解决方案1】:

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

【讨论】:

  • 顺便说一句,如果您在 Google 上搜索“支持数据绑定的 WPF 饼图”,那么该项目包含一个名为“PiePiece”的形状类,它似乎完全符合您的要求。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-20
    • 2016-07-05
    • 1970-01-01
    • 2021-07-22
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多