Recently I’ve been trying to learn more about WPF, since WinForms is getting really old now. As a small exercise I was trying to create a custom Shape, so I created a new class, derived it from Shape and started following this tutorial untill I found out that you can’t override the DefiningGeometry method in Silverlight.

After some searching I found this MSDN Blog article, where in Silverlight a custom shape is created by extending from Path (well I wouldn’t have thought of that).

After a bit of tweaking I adapted the class to display a Hexagon instead of a Triangle:

namespace MyProject.Shapes
    public class Hexagon : Path
        public Hexagon()
            CreateDataPath(0, 0);

        private void CreateDataPath(double width, double height)
            height -= this.StrokeThickness;
            width -= this.StrokeThickness;

            //Prevent layout loop
            if(lastWidth == width && lastHeight == height)

            lastWidth = width;
            lastHeight = height;

            PathGeometry geometry = new PathGeometry();
            figure = new PathFigure();

            //See for figure info
            figure.StartPoint = new Point(0.25 * width, 0);
            AddPoint(0.75 * width, 0);
            AddPoint(width, 0.5 * height);
            AddPoint(0.75 * width, height);
            AddPoint(0.25 * width, height);
            AddPoint(0, 0.5 * height);
            figure.IsClosed = true;
            this.Data = geometry;

        private void AddPoint(double x, double y)
            LineSegment segment = new LineSegment();
            segment.Point = new Point(x + 0.5 * StrokeThickness,
                y + 0.5 * StrokeThickness);

        protected override Size MeasureOverride(Size availableSize)
            return availableSize;

        protected override Size ArrangeOverride(Size finalSize)
            CreateDataPath(finalSize.Width, finalSize.Height);
            return finalSize;            

        #region FieldsAndProperties
        private double lastWidth = 0;
        private double lastHeight = 0;
        private PathFigure figure;

You can use a ‘shape’ like this in XAML:

<UserControl x:Class="FantasyCartographer.MainPage"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Canvas Height="161" HorizontalAlignment="Left" Margin="27,32,0,0" Name="canvas1" VerticalAlignment="Top" Width="254">
            <Shapes:Hexagon Canvas.Left="0" Canvas.Top="0" Height="154" x:Name="hexagon1" Stroke="Black" StrokeThickness="3" Width="188" Fill="Red"  />            

Tip: don’t forget to define an xmlns namespace mapping to your own .NET namespaces so that you can use a shape even if you defined it in another namespace, I’ve done this in the above XAML code as an example.