如何在构造函数中使自定义形状类可见

时间:2012-03-05 16:18:41

标签: c# wpf silverlight windows-phone

我正在尝试创建一个自定义形状类,它基本上是一个六边形,但没有额外的属性和方法。

我尝试从Polygon类继承它,但它不允许它,因为Polygon类是密封的,所以我从抽象的Shape类继承它,但是不要我不知道接下来该做什么。到目前为止,我的代码看起来像这样

public class Cell : Shape
{
    private Polygon poly;
    private Point[] points = new Point[6];
    public PointCollection Points { get; set; }
    public double Radius { get; set; }
    public Point Center { get; set; }
    public Cell()
    {
        points[0] = new Point(Center.X - 1 / 2 * Radius, Center.Y - Radius * 0.866);
        points[1] = new Point(Center.X + 1 / 2 * Radius, Center.Y - Radius * 0.866);
        points[2] = new Point(Center.X + Radius, Center.Y);
        points[3] = new Point(Center.X + 1 / 2 * Radius, Center.Y + Radius * 0.866);
        points[4] = new Point(Center.X - 1 / 2 * Radius, Center.Y + Radius * 0.866);
        points[5] = new Point(Center.X - Radius, Center.Y);

        Points = new PointCollection();
        foreach (Point p in points)
            Points.Add(p);
        poly = new Polygon();
        poly.Points = this.Points;
    }
}

现在,我希望能够在XAML中声明它:

<local:Cell Center="20,20" Radius="10" Stroke="Blue" Fill="White"/>

我还希望它在构造函数中可见。

我还需要在课堂上添加什么才能做到这一点?是否需要实现某个界面或需要覆盖的方法?

1 个答案:

答案 0 :(得分:2)

我做了类似的事情以产生半圆形状。您需要从Shape继承并覆盖DefiningGeometry和MeasureOverride。在DefiningGeometry中,您将执行实际绘制并返回几何体。

要使您在XAML中可见的属性,您只需要为您的类添加属性。将显示纯.NET属性,但您可能希望添加依赖项属性并设置AffectsRender FrameworkPropertyMetadataOptions,以便在更改属性时强制重绘。

这是我班级的样子:

public class SemiCircle : Shape
{
    /// <summary>
    /// Gets or set the alignment of the semicircle. I.e. where should the flat part point.
    /// </summary>
    public SemiCircleAlignment Alignment
    {
        get { return (SemiCircleAlignment)GetValue(AlignmentProperty); }
        set { SetValue(AlignmentProperty, value); }
    }

    // Using a DependencyProperty as the backing store for alignment.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AlignmentProperty =
        DependencyProperty.Register("Alignment", typeof(SemiCircleAlignment), typeof(SemiCircle), 
        new FrameworkPropertyMetadata(SemiCircleAlignment.Top,FrameworkPropertyMetadataOptions.AffectsRender));

    protected override System.Windows.Media.Geometry DefiningGeometry
    {
        get 
        {
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext context = geometry.Open())
            {
                DrawSemiCircle(context);
            }
            geometry.Freeze();
            return geometry;
        }
    }

    protected override Size MeasureOverride(Size constraint)
    {
        if (constraint.Height == double.PositiveInfinity || constraint.Width == double.PositiveInfinity)
        {
            if (double.IsNaN(Width) || double.IsNaN(Height))
            {
                return new Size(0, 0);
            }
            return new Size(Width, Height);
        }
        return constraint;
    }

    private void DrawSemiCircle(StreamGeometryContext context)
    {
        double tOff = StrokeThickness / 2.0;                // an offset to account for stroke thickness
        Point startPt = new Point(tOff, tOff);                                   // upper left corner
        if (Alignment == SemiCircleAlignment.Bottom || Alignment == SemiCircleAlignment.Right)
        {
            startPt = new Point(ActualWidth - tOff, ActualHeight - tOff);        // or lower right corner
        }
        Point endPt = new Point(ActualWidth - tOff,tOff);                         // upper right corner
        if (Alignment == SemiCircleAlignment.Left || Alignment == SemiCircleAlignment.Bottom)
        {
            endPt = new Point(tOff, ActualHeight - tOff);                         // or lower left corner
        }
        Size s = new Size(Math.Max(0.0,(ActualWidth / 2) - tOff), 
            Math.Max(0,ActualHeight - StrokeThickness));    // half width is radius
        SweepDirection sweep = SweepDirection.Counterclockwise;    
        if (Alignment == SemiCircleAlignment.Left || Alignment == SemiCircleAlignment.Right)
        {
            s = new Size(Math.Max(0,ActualWidth - StrokeThickness),
                Math.Max(0.0,(ActualHeight / 2) - tOff));     // or half height is radius
            sweep = SweepDirection.Clockwise;
        }

        context.BeginFigure(startPt, true, true);
        context.ArcTo(endPt, s, 0, false, sweep, true, false);
    }
}

public enum SemiCircleAlignment { Left, Top, Right, Bottom };