Subclassing Shape (or more accurately, Path)
One of the more subtle improvements in Silverlight 4 is that we unsealed the Path class. That means you can write a class that behaves like a shape without re-implementing properties like Fill, Stroke, etc. -- just subclass, set Path.Data to render what you want, and provide Measure/Arrange appropriate functionality. (Existing Shapes don't all use the same measure/arrange logic) Here's a sample Triangle class:
public class Triangle : Path
{
public Triangle()
{
CreatePathData(0,0);
}
private double lastWidth = 0;
private double lastHeight = 0;
private PathFigure figure;
private void AddPoint(double x, double y)
{
LineSegment segment = new LineSegment();
segment.Point = new Point(x + 0.5 * StrokeThickness,
y + 0.5 * StrokeThickness);
figure.Segments.Add(segment);
}
private void CreatePathData(double width, double height)
{
// in order to fit in our layout slot we need to reduce the size of the stroke
height -= this.StrokeThickness;
width -= this.StrokeThickness;
// needed to avoid a layout loop
if (lastWidth == width && lastHeight == height) return;
lastWidth = width;
lastHeight = height;
var geometry = new PathGeometry();
figure = new PathFigure();
figure.StartPoint = new Point(0 + 0.5 * StrokeThickness, height + 0.5 * StrokeThickness);
AddPoint(width, height);
AddPoint(width / 2, 0);
AddPoint(0, height);
figure.IsClosed = true;
geometry.Figures.Add(figure);
this.Data = geometry;
}
protected override Size MeasureOverride(Size availableSize)
{
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
CreatePathData(finalSize.Width, finalSize.Height);
return finalSize;
}
}
Enjoy!