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.
Hello,could you post this as project or solution please? I would like to use this donut class in my project..Thnx
LikeLike
Me too
LikeLike
I reconstructed the project and posted to GitHub.
LikeLike
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); }
LikeLike
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);
LikeLike
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; } }
LikeLike
A very nice sample but it is valueless since there is not a solution to test !…
LikeLike
I posted my code to GitHub. Check it out.
LikeLike