Donut Shape in WPF
Its true that you can do a lot of very interesting things with path manipulation inside Expression Blend but there is no way to programmatically do such combine operations. The output of a Blend path combination is a new path whose points are fixed. This means that any scaling transformations are going to cause loss of fidelity of your new shape.
Luckily WPF & Silverlight have the ability to create your own custom Shape classes. Below is my code:
private void DrawArrowGeometry(StreamGeometryContext context)
{
// Setup the Center Point & Radius
Point c = new Point(ActualWidth / 2, ActualHeight / 2);
double rOutterX = ActualWidth / 2;
double rOutterY = ActualHeight / 2;
double rInnerX = rOutterX - InnerWidth;
double rInnerY = rOutterY - InnerWidth;
double theta = 0;
bool hasBegun = false;
double x;
double y;
Point currentPoint;
// Draw the Outside Edge
for (theta = StartAngle; theta <= StopAngle; theta++)
{
x = c.X + rOutterX * Math.Cos(GetRadian(theta));
y = c.Y + rOutterY * Math.Sin(GetRadian(theta));
currentPoint = new Point(x, y);
if (!hasBegun)
{
context.BeginFigure(currentPoint, true, true);
hasBegun = true;
}
context.LineTo(currentPoint, true, true);
}
// Connect the Outside Edge to the Inner Edge
x = c.X + rInnerX * Math.Cos(GetRadian(StopAngle));
y = c.Y + rInnerY * Math.Sin(GetRadian(StopAngle));
currentPoint = new Point(x, y);
context.LineTo(currentPoint, true, true);
// Draw the Inner Edge
for (theta = StopAngle; theta >= StartAngle; theta--)
{
x = c.X + rInnerX * Math.Cos(GetRadian(theta));
y = c.Y + rInnerY * Math.Sin(GetRadian(theta));
currentPoint = new Point(x, y);
context.LineTo(currentPoint, true, true);
}
// Connect the Inner Edge to the Outside Edge
x = c.X + rOutterX * Math.Cos(GetRadian(StartAngle));
y = c.Y + rOutterY * Math.Sin(GetRadian(StartAngle));
currentPoint = new Point(x, y);
context.LineTo(currentPoint, true, true);
context.Close();
}
After adding dependency properties for Start Angle, StopAngle, and InnerWidth. Here is the result:
<local:Donut Width="100" Stroke="Black" StrokeThickness="2" HorizontalAlignment="Left" Margin="18,106,0,58" Height="100" InnerWidth="35" StopAngle="180" >
<local:Donut.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FFCC1F1F" Offset="1"/>
</LinearGradientBrush>
</local:Donut.Fill>
</local:Donut>
<local:Donut StrokeThickness="2" Margin="0,42,41,122" Height="100" HorizontalAlignment="Right" Width="100" InnerWidth="10" d:LayoutOverrides="Height" >
<local:Donut.Fill>
<RadialGradientBrush>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
<GradientStop Color="#FFFF7400" Offset="0.71"/>
</RadialGradientBrush>
</local:Donut.Fill>
</local:Donut>
<local:Donut StrokeThickness="2" Margin="0,0,41,8" Height="100" HorizontalAlignment="Right" Width="100" InnerWidth="10" VerticalAlignment="Bottom" d:LayoutOverrides="Height" StopAngle="225" Stroke="#FF000000" >
<local:Donut.Fill>
<RadialGradientBrush>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
<GradientStop Color="#FFFF0000" Offset="0.536"/>
</RadialGradientBrush>
</local:Donut.Fill>
</local:Donut>
UPDATE:
I reconstructed the project and posted the code to GitHub. There appears to be a bug in the reconstructed code such that as you resize the window it will continuously get bigger.