# 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>
</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>
</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>
</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.

## 8 thoughts on “Donut Shape in WPF”

1. Unknown

Hello,could you post this as project or solution please? I would like to use this donut class in my project..Thnx

Like

• valentinvbadeaValentin

Me too

Like

• Heimdall

I reconstructed the project and posted to GitHub.

Like

2. Brian

For those of you that didn’t know what the GetRadian implementation was: private double GetRadian(double angle) { return (Math.PI / 180.0) * (angle – 90); }

Like

3. Brian

I didn’t want a line on the wedge if the wedge was a circle or a ring …So didn’t stroke the line if my angle was 360 …context.LineTo(currentPoint, Angle != 360, true);

Like

4. Brian

The implementation presented is a bit different then mine …I have a rotation angle, and wedge angle …So start angle translates to rotation angle …stop angle translates to rotation angle + wedge angle …I wrapped wedge angle to do some checking …public double Angle { get { double rc = WedgeAngle; if (WedgeAngle > 360) { rc = WedgeAngle % 360; if (rc == 0) { rc = 360; } } return rc; } }

Like

5. valentinvbadeaValentin

A very nice sample but it is valueless since there is not a solution to test !…

Like

• Heimdall

I posted my code to GitHub. Check it out.

Like