Recently I started playing around with the creation of a Silverlight application of C#; leaving my comfort zone of doing Silverlight development solely in IronRuby. The project that I decided to start is an application that is similar to the famous "Wheel of Lunch", which will essentially query the Windows Live Search phonebook web service for any number of criteria (I am not limiting it to places to eat, you can choose to search hardware stores if you’d like), and have it populate what I am now calling the "Wheel of Choice" with the search results, it will then allow the user to spin the wheel, and the app will provide the user with their choice.
My adventure with Silverlight paths started as I was trying to figure out how to render the wheel. I wanted to keep this Silverlight user control as flexible as possible, so that I could easily use it in other projects. The requirements that I put forth were:
- the wheel size must be customizable
- the wheel must be able to be split into any number of sections
- the sections of the wheel must be rendered to be of equal size
- each section must be labeled with text passed in to the control(to represent a choice)
It was necessary to generate each section of the wheel separately, so that each section could be it’s own element. The Path element is the most flexible solution, it’s Data attribute essentially contains instructions on where to draw random lines and curves on the canvas. Looking at Path data can be daunting, it looks like a bunch of letters and numbers concatenated together, and to the blind eye, it really does not tell you a whole lot (example: "M 10100 C 10300 300,-200 250100z").
In doing a little research I found out that the data string is made up of a Path sub-language, I find it similar to the old Turtle graphics programs, only it’s definitely made for grown-ups. A reference to the Path syntax is found here. While I completely understand that you can make up a path’s data by using a bunch of geometry elements, I wanted more of a challenge so I decided to dynamically build the paths for each section using the Path syntax.
The control was created with two public properties:
Radius takes care of the overall size of the wheel, and SectionLabel defines the tool tip to set on each section (as well as defines the number of sections needed on the wheel). Some private properties are also used to be used globally throughout the user control:
_sectionCount places the total number of sections in a value type, just so that it’s not necessary to keep pulling the SectionLabels.Count property. _theta is the angle that is used to identify endpoints on the edge of the wheel. _colors is an array used to assign a color to each section created. Setting of these values and the calculation of _theta is as follows:
As specified before, _theta is used to find the evenly-spaced endpoints around the circle which will make up the sections. The method to calculate these endpoints is as follows (where section is simply the index of the section being rendered):
Putting it all together, the RenderWheel() public method takes care of calculating the endpoints as well as defining the Path. The first lesson learned is that you cannot directly assign the generated path data string to a Path’s data attribute, it must be of type Geometry. To get around this issue, the XAML for the path is instead generated with the string value in the data attribute, then cast back into a Path element and then added to the visual root of the user control. Do not forget to include the namespaces in this generated XAML. The well-commented listing of the RenderWheel method is as follows:
For sake of completeness, here is the XAML of the user control (only an empty canvas):
The complete code-behind for this control can be found here . The final result (though not very pretty) looks like this: