我正在尝试创建一个自定义形状类,它基本上是一个六边形,但没有额外的属性和方法。
我尝试从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"/>
我还希望它在构造函数中可见。
我还需要在课堂上添加什么才能做到这一点?是否需要实现某个界面或需要覆盖的方法?
答案 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 };