In a previous post, I mentioned that I developed a MeasureString function for use in developing an annotation tool. In this post, I’ll go into a little bit more detail about that tool. For purposes of discussion, I extended the interactive graphics sample from the Esri Silverlight API interactive SDK.
For starters, I added another tool to the sample’s tool bar (circled in red below) to provide access to the annotation capability.
The User’s View
To kick things off from a user’s perspective, you have to first click the tool on the toolbar to activate it and then click a location on the map where you would like your annotation to appear. In order to keep things simple this time around, I am only supporting centering the text on the selected point. After you click on the map, a Silverlight child window is displayed, as shown below, allowing you to type in your text and set other properties such as font and size (I plan to add a color picker soon).
Once you set your various annotation properties, click “OK” to dismiss the child window and your annotation will appear on the map control, centered on the point you clicked. In this case, I set the font to Times New Roman and the size to 16.
That’s the basic user-centric process. I took it a step further and added a context menu tied to a right mouse click on a piece of text. This context menu allows you to delete the text or to edit it. If you choose to edit, it simply displays the child window again, showing the properties of the text you selected.
Under the Hood
That’s relatively simple. So what’s happening to make it work? Let’s walk through the procedure above from a code-centric view point.
When you click the tool on the toolbar, you are activating a class behind the tool. The activation method sets up a Draw object in point mode like so:
1 2 3 4 5 6 7 8
When you click on the map, the Draw object’s DrawComplete event is fired. The event handler simply displays the child window like so:
1 2 3 4 5 6 7 8
At this point, the child window is displayed and you can set the text properties as you see fit. The code in the window itself really does nothing other than manage the window display. If you change the font, it is reflected in the textbox, as is the font size so that you can see what your annotation will look like. The heavy lifting is really done once the window is closed.
This where the other key object from the Esri Silverlight API comes into play: the TextSymbol object. In order to draw the text, the code creates a graphic object using the point geometry captured on the mouse click and symbolizes it using a text symbol instead of an icon or some other marker symbol. That work all happens in the child window’s Closed event as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
That’s the core of the work. You’ll notice above that we use OffsetX and OffsetY to center the text. These values are in screen units as opposed to map units and this is why we need to know the size of the text string. The call to the “Measure” method is a call to the extension method I described here. You’ll also notice that I don’t set the font weight or style. That’s because the TextSymbol object doesn’t seem to support those attributes yet. I could probably play with using styles to accomplish that but it wasn’t necessary for this iteration. There also doesn’t seem to be a built-in way to control rotation or scaling. Those may be able to be accomplished by other means but were not necessary for this iteration, either.
From here, you can go on to implement things like the context menu as you see fit. A couple of notes on some specifics: In the child window, I used the numeric up/down control from the Silverlight Toolkit. For the context menu, I used the SL4PopupMenu from Codeplex. I found the context menu from the Silverlight Toolkit didn’t behave as expected when attaching events to map graphics.
So that was the basic process I followed for implementing simple, interactive annotations using the Esri Silverlight API. I’ll try to get a working demo posted up soon.