Dec 14

The purpose of this post is to create an interactive map that allows you to select multiple regions of a map. To do this we create a customized template based on a "ToggleButton. Indeed, thanks to "ToggleButton" we're going to manage several status as "Checked" and "Unchecked" which will serve us whether the region is selected or not.
For this post we'll use a map of Belgium where you can select multiple provinces. Then, all selected provinces will be added to a list.

Step 1 Creation of template for “ToggleButton”

The first step in creating this map is to add a “ToggleButton”, then click in the list at the top left and select:

Edit Template --> Create Empty…

image

To follow the boundaries of the map we use the "Pen" to define a "Path". Since an element can be amended only by a “VisualStateGroup”, we will create 2 “Path”. One for the group “CommonStates” and one for the group “CheckStates”.

image

The 2 "Path" are identical no matter the data they contain.

<Path Fill="White" Stretch="Fill" Stroke="Black" Height="68" HorizontalAlignment="Left" Margin="35.5,24.5,0,0" VerticalAlignment="Top" Width="75" UseLayoutRounding="False" Data="M64,25 L110,55 L36,92 z"/>
<Path Fill="Black" Stretch="Fill" Stroke="Black" Height="68" HorizontalAlignment="Left" Margin="35.5,24.5,0,0" VerticalAlignment="Top" Width="75" UseLayoutRounding="False" Data="M64,25 L110,55 L36,92 z"/>

For simplicity I named the "Path", "PathCommonStates" and "PathCheckStates", and I Initialize their opacities to 0.

image

image

Then I select the path "PathCommonState" and click on the "MouseOver" state to change the opacity to 30%.

image

I do the same thing with the path "PathCheckStates", I click on "Checked" state to set the opacity to 30%.
I will then modify the code to add "TemplateBinding" properties. It gives this:

<UserControl.Resources>
	<ControlTemplate x:Key="MapButton" TargetType="ToggleButton">
		<Grid>
			<VisualStateManager.VisualStateGroups>
				<VisualStateGroup x:Name="CommonStates">
					<VisualState x:Name="Normal"/>
					<VisualState x:Name="MouseOver">
						<Storyboard>
							<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PathCommonStates" Storyboard.TargetProperty="(UIElement.Opacity)">
								<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0.3"/>
							</DoubleAnimationUsingKeyFrames>
						</Storyboard>
					</VisualState>
					<VisualState x:Name="Pressed"/>
					<VisualState x:Name="Disabled"/>
				</VisualStateGroup>
				<VisualStateGroup x:Name="CheckStates">
					<VisualState x:Name="Unchecked"/>
					<VisualState x:Name="Indeterminate"/>
					<VisualState x:Name="Checked">
						<Storyboard>
							<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PathCheckStates" Storyboard.TargetProperty="(UIElement.Opacity)">
								<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0.3"/>
							</DoubleAnimationUsingKeyFrames>
						</Storyboard>
					</VisualState>
				</VisualStateGroup>
				<VisualStateGroup x:Name="FocusStates">
					<VisualState x:Name="Unfocused"/>
					<VisualState x:Name="Focused"/>
				</VisualStateGroup>
			</VisualStateManager.VisualStateGroups>
			<Path x:Name="PathCommonStates" Opacity="0" Fill="White" Stretch="Fill" Height="{TemplateBinding Height}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Margin}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Width="{TemplateBinding Width}" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Data="{TemplateBinding Content}"/>
			<Path x:Name="PathCheckStates" Opacity="0" Fill="Black" Stretch="Fill" Height="{TemplateBinding Height}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Margin}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Width="{TemplateBinding Width}" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Data="{TemplateBinding Content}"/>
		</Grid>
	</ControlTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
	<ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top" Content="ToggleButton" Template="{StaticResource MapButton}"/>
</Grid>

Note that the property "Data" is doing a "TemplateBinding" on the property "Content". Indeed, we will use the property "Content" of "ToggleButton" to the boundaries of each region.

Step 2: Adding the map into the project


After the creation of “ToggleButton”, we will simply add the map into the project.

Step 3: Establish the boundaries of each region


The third step is creating the boundaries of each region, we will then take the "Pen" and create a "Path" point by point all around the region. Like this:

image

Then we copy all the properties of the "Path" in the customized "ToggleButton" except that "Data" property is renamed "Content" property and "Stretch" is deleted.
Example:

<Path Stretch="Fill" Height="95.333" Margin="282.667,128.5,216.667,0" VerticalAlignment="Top" UseLayoutRounding="False" Data="…"/>

Becomes:

<ToggleButton Template="{StaticResource MapButton}" Height="95.333" Margin="282.667,128.5,216.667,0" VerticalAlignment="Top" UseLayoutRounding="False" Content="…"/>

 

You can download the full code:

Tags:

Comments

Irwin Fletcher

Posted on Friday, 8 January 2010 11:51

This is a great post, it helped me get a better handle on the map application that I am messing around with.  How would you implement a zoom and pan feature with a XAML image?

Chapel Hill Houses for Sale

Posted on Saturday, 6 February 2010 09:57

This is why I love using Silverlight, it's fun, easy & innovative. Thanks for sharing this post.

Add comment




  Country flag

biuquote
Loading