# Introduction

Click here to view source code

Over the years I have been presented with many different situations while programming in WPF, which required a certain Control or class to be created to accommodate. Given all the various solutions I created throughout the years I thought it might be helpful to someone else. During this ongoing series I am going to post some of the more useful classes I have made in the past.

# Simple Pie Chart

In one project I was assigned to redesign, there was data coming in that we wanted represented in the form of a pie chart. Initially, we simply displayed the information in the form of one out of many static pie chart images. A specific image would get selected based on what the percentage was closest. Although this solved our immediate needs I believed generating this with GeometryDrawing would make the chart much more accurate and should not be too difficult to create. My immediate goal was to try and represent some type of pie chart in XAML to get an idea of how it could be represented dynamically. Initial searching led to this solution involving dividing a chart into thirds. Following the example given will produce a subdivided geometric ellipse:

# Programmatically Build Chart

Unfortunately, using strictly XAML will not work when attempting to create a pie chart dynamically. This is definitely a great starting point in how we could create this Control, but I needed a better understanding how to create geometric objects programmatically. Doing some more searching I came across this Code Project that describes how to create pie charts from code. My pie chart will be much simpler containing only two slices and taking in a percentage value to represent how the slices will subdivide. I still use an Image to represent how the geometry will be drawn and begin the creation of the root elements:

`_pieChartImage.Width = _pieChartImage.Height = Width = Height = Size;` `var` `di = ` `new` `DrawingImage();` `_pieChartImage.Source = di;` `var` `dg = ` `new` `DrawingGroup();` `di.Drawing = dg;` |

Since I know my starting point of the pie will always be at the top I then calculate where my line segment will end (the PieSliceFillers are brushes representing the fill color):

`var` `angle = 360 * Percentage;` `var` `radians = ( Math.PI / 180 ) * angle;` `var` `endPointX = Math.Sin( radians ) * Height / 2 + Height / 2;` `var` `endPointY = Width / 2 - Math.Cos( radians ) * Width / 2;` `var` `endPoint = ` `new` `Point( endPointX, endPointY );` `dg.Children.Add( CreatePathGeometry( InnerPieSliceFill, ` `new` `Point( Width / 2, 0 ), endPoint, Percentage > 0.5 ) );` `dg.Children.Add( CreatePathGeometry( OuterPieSliceFill, endPoint, ` `new` `Point( Width / 2, 0 ), Percentage <= 0.5 ) );` |

My CreatePathGeometry method creates both the inner and outer pie slices using a starting point, the point where the arc will end, and a boolean for ArcSegment to determine how the arc should get drawn if greater than 180 degrees.

`private` `GeometryDrawing CreatePathGeometry( Brush brush, Point startPoint, Point arcPoint, ` `bool` `isLargeArc )` `{` ` ` `var` `midPoint = ` `new` `Point( Width / 2, Height / 2 );` ` ` `var` `drawing = ` `new` `GeometryDrawing { Brush = brush };` ` ` `var` `pathGeometry = ` `new` `PathGeometry();` ` ` `var` `pathFigure = ` `new` `PathFigure { StartPoint = midPoint };` ` ` `var` `ls1 = ` `new` `LineSegment( startPoint, ` `false` `);` ` ` `var` `arc = ` `new` `ArcSegment` ` ` `{` ` ` `SweepDirection = SweepDirection.Clockwise,` ` ` `Size = ` `new` `Size( Width / 2, Height / 2 ),` ` ` `Point = arcPoint,` ` ` `IsLargeArc = isLargeArc` ` ` `};` ` ` `var` `ls2 = ` `new` `LineSegment( midPoint, ` `false` `);` ` ` `drawing.Geometry = pathGeometry;` ` ` `pathGeometry.Figures.Add( pathFigure );` ` ` `pathFigure.Segments.Add( ls1 );` ` ` `pathFigure.Segments.Add( arc );` ` ` `pathFigure.Segments.Add( ls2 );` ` ` `return` `drawing;` `}` |

A better to visualize this is through a XAML representation:

<GeometryDrawing Brush="@Brush"> <GeometryDrawing.Geometry> <PathGeometry> <PathFigure StartPoint="@Size/2"> <PathFigure.Segments> <LineSegment Point="@startPoint"/> <ArcSegment Point="@arcPoint" SweepDirection="Clockwise" Size="@Size/2"/> <LineSegment Point="@Size/2"/> </PathFigure.Segments> </PathFigure> </PathGeometry> </GeometryDrawing.Geometry> </GeometryDrawing>

And with that we are able to create quick an easy pie charts as shown here:

# Multi Pie Chart

Although this is suitable for a two sided pie chart, but what if you wanted more? That process is pretty straight forward based off what we already created. By including two dependency properties to represent our collection of data and brushes, we only need to rewrite how my segments are created:

`var` `total = DataList.Sum();` `var` `startPoint = ` `new` `Point( Width / 2, 0 );` `double` `radians = 0;` `for` `( ` `int` `i = 0; i < DataList.Count; i++ ) { ` `var` `data = DataList[i]; ` `var` `dataBrush = GetBrushFromList( i ); ` `var` `percentage = data / total; Point endPoint; ` `var` `angle = 360 * percentage; ` `if` `( i + 1 == DataList.Count ) { endPoint = ` `new` `Point( Width / 2, 0 ); } ` `else` `{ radians += ( Math.PI / 180 ) * angle; ` `var` `endPointX = Math.Sin( radians ) * Height / 2 + Height / 2; ` `var` `endPointY = Width / 2 - Math.Cos( radians ) * Width / 2; endPoint = ` `new` `Point( endPointX, endPointY ); } dg.Children.Add( CreatePathGeometry( dataBrush, startPoint, endPoint, angle > 180 ) );` ` ` `startPoint = endPoint;` `}` |

As you can see, the main difference is now we are accumulating the radians as we traverse the list to take into account any number of data objects. The result allows us to add any number of data items to our pie chart as shown here:

# Conclusion

Although I did not get as much use for this class as I would have preferred, developing this helped me gain experience in manipulating geometry objects, which does not happen often enough.

Pingback: WPF Round Table Part 2: Multi UI Threaded Control | Just Coding Things

Pingback: WPF Round Table Part 2: Multi UI Threaded Control – Fixes | Just Coding Things