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…
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”.
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.
Then I select the path "PathCommonState" and click on the "MouseOver" state to change the opacity to 30%.
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:
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: