We pay for user submitted tutorials and articles that we publish. Anyone can send in a contributionLearn More
This article was written by Alan Mendelevich
Creating a shape with bullets on the joints of it’s segments sounds like a really trivial task at a first glance. Just plaster some bullets on top of the shape. And it is really something like this until you decide you want to have transparent outlined bullets or opaque bullets with transparent outline around them. Like the ones in this picture:
If you have a simplistic figure like the first rectangle in the above picture you may think about just creating shorter lines for it’s sides. This is not a very complicated task. However in the second (triangle) example calculating the end points for the lines gets a little more complicated. And try doing this without a masters degree in mathematics for the third and fourth (bottom) examples utilizing arcs and Bezier curves.
The second option is to cheat a little. You can use background color for bullet’s fill or outline. This would work well on a solid color background. But what if you have a gradient background (like in our sample picture), image background or if your bullet falls on the edge of some object or the shape itself?
The magic word for my solution is OpacityMask. To quote MSDN documentation what it does is:
Gets or sets an opacity mask, as a Brush implementation that is applied to any alpha-channel masking for the rendered content of this element.
In other words it lets you apply different levels of opacity to different portions of your element.
So, the general idea is to create an opacity mask which has zero opacity spots in place where we want to put our bullets and 100% opacity everywhere else. Below are the main parts of the implementation along with some small but very important details.
With all this done (you can see the implementation by downloading the source code for the control linked at the end of the article) we override OnRender method of our shape.
Here’s the method in it’s entirety and we’ll examine what it does below:
First we construct a pen to use for drawing the outline of our shape. Oddly enough Shape class doesn’t provide one property for setting the Pen. This is justified by the fact that it’s easier to set (and animate) individual properties of the pen on the whole shape object in XAML rather than creating a dedicated object for the outline pen.
This is understandable, however it would be really nice of Microsoft to provide a method to get a real Pen out of all these individual properties. This is a good candidate for an extension method, but that’s another story and for now we just construct the pen manually.
Now comes a tricky part.
We need to construct our opacity mask. Opacity mask is a Brush and it gets applied to the whole drawing area of the element. The size of that area depends not only on the geometry of our shape but on the size of it’s stroke, it’s miter, etc. For example if you have a line from point (0, 0) to (0, 100) and the StrokeThickness is set to 100 you’d get a line that (at the very least) occupies space from -50 to 50 on the Y-axis and it could be more dependent on the caps of that line and other settings. So, in order to get the final bounds of our shape before we actually draw it we create a temporary drawing using our actual pen settings and use it’s bounds as a rectangle area for our mask:
Then we get the geometries for our bullet holes (see the source code for details) and exclude them from our rectangular area. This way we get a geometry which is a rectangle with a holes in it.
Now we need to create a brush for our opacity mask from this geometry.
We create a GeometryDrawing using any opaque brush for it’s fill (Brushes.Black for example) and create a DrawingBrush from this drawing. It’s important to set brush’s Stretch property to None so it’s not distorted in any way.
And now all that’s left is to push our opacity mask on a DrawingContext, draw our shape (opacity mask will make sure that there are holes on the junction points), pop the mask and draw the bullets:
And that’s it.
I’ve omitted implementations of the other reasonably trivial tasks like drawing the bullets from the article but you can always take a look at the implementation by downloading the source code of BulletedPath control.
About the author: Alan Mendelevich is a software developer from Vilnius, Lithuania. He has more than 10 years of professional software development experience for both Web and Windows. Currently he works as a lead developer on amCharts for WPF project – a charting control suite for WPF platform and SPAW Editor – open source web based WYSIWYG HTML editor control.
Copyright © 2012 Dev102.com
Breeze : Designed by Amit Raz and Nitzan Kupererd