Thursday, November 18, 2010

Context Menu with check mark

In Silverlight 4 it is very easy to create a context menu, basically a context menu appears on right click action and has choices depending on the state of the UI element. Silverlight toolkit has a in build context menu control, if you do not have the toolkit you will have to install it from Microsoft website. Once installed you can add context menu control to your visual studio toolbox by doing a right click on toolbox –> Choose Items…-> Silverlight Components –>select ContextMenu and press ok. Now you can drag and drop the context menu from the toolbox in your layout editor, a name space xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" should be added to the XAML and three dll’s will be added in the project references

image

In the main page XAML add the below code, here we have a text box with a context menu it has two items one has a Icon and the next item does not have a icon. Our intention is to show a check mark in front of the menu item when a user first time clicks on the menu and toggle it on consecutive clicks. To display a icon in front the toolkit has element called <MenuItem.Icon> the icon is of type content so it can be anything like a image, textbox, grid. I could have select a Image of a check mark and used it as icon but the problem is my application has numerous themes where the user can change the color of every item in UI, so in this case we will have to create different image for each an every color. Instead of Image I use a textblock that will have the ascii equivalent of the check mark and surround the textblock with a Border. To display ascii character in textblock we should use the format “&#<ascii code>;”

  1:   <Grid x:Name="LayoutRoot" Background="White">
  2:         <TextBox Text="Context Menu test" Height="200" Width="200" >
  3:             <toolkit:ContextMenuService.ContextMenu>
  4:                 <toolkit:ContextMenu>
  5:                     <toolkit:MenuItem x:Name="AlertWindow" Header="Display Window" 
  6:                                       Click="AlertWindow_Click" >
  7:                         <toolkit:MenuItem.Icon>
  8:                             <Border BorderBrush="Blue" Background="LightBlue"
  9:                                     BorderThickness=".5"  >
 10:                                 <TextBlock Text="&#8730;" FontWeight="Bold" 
 11:                                      Foreground="Green" TextAlignment="Center"/>
 12:                             </Border>
 13:                         </toolkit:MenuItem.Icon>
 14:                     </toolkit:MenuItem>
 15:                     <toolkit:MenuItem x:Name="Close" Header="Close" >
 16:                     </toolkit:MenuItem>
 17:                 </toolkit:ContextMenu>
 18:             </toolkit:ContextMenuService.ContextMenu>
 19:         </TextBox>
 20:     </Grid>

Now you can add a click event on the menu item, and in the xaml.cs add a event handler. The code shown below will basically toggle the visibility of the border.

  1:     private void AlertWindow_Click(object sender, RoutedEventArgs e)
  2:     {
  3:         Border border = ((sender as MenuItem).Icon as Border);
  4:         if(border.Visibility==Visibility.Collapsed)
  5:             border.Visibility = Visibility.Visible;
  6:         else
  7:             border.Visibility = Visibility.Collapsed;
  8:     }


The final output in the browser will look like this
image
Additional benefit of this technique is modularity and maintainability because you do not need different images for differently themed application.One can easily match the color of the context menu check mark icon with the theme of your application as the colors are stored in resources. For simplicity I will keep the theme color’s in the <UserControl.Resources> but for your application the theme location might in a resource dictionary, the final XAML should look like this .

  1:     <UserControl.Resources>
  2:         <SolidColorBrush x:Name="MenuTickBorderColor" Color="Brown"/>
  3:         <SolidColorBrush x:Name="MenuTickFillColor" Color="Yellow"/>
  4:         <SolidColorBrush x:Name="MenuTickFontColor" Color="Brown"/>
  5:     </UserControl.Resources>
  6:    
  7:     <Grid x:Name="LayoutRoot" Background="White">       
  8:         <TextBox Text="Context Menu test" Height="200" Width="200" > 
  9:             <toolkit:ContextMenuService.ContextMenu>
 10:                 <toolkit:ContextMenu>
 11:                     <toolkit:MenuItem x:Name="AlertWindow" Header="Display Window"
 12:                                       Click="AlertWindow_Click" >
 13:                         <toolkit:MenuItem.Icon>
 14:                             <Border BorderBrush="{StaticResource MenuTickBorderColor}"
 15:                                     Background="{StaticResource MenuTickFillColor}"
 16:                                     BorderThickness=".5"  >
 17:                                 <TextBlock Text="&#8730;" FontWeight="Bold"
 18:                                            Foreground="{StaticResource MenuTickFontColor}"
 19:                                            TextAlignment="Center"    />
 20:                             </Border>
 21:                         </toolkit:MenuItem.Icon>
 22:                     </toolkit:MenuItem>
 23:                     <toolkit:MenuItem x:Name="Close" Header="Close" >                      
 24:                     </toolkit:MenuItem>
 25:                 </toolkit:ContextMenu>
 26:             </toolkit:ContextMenuService.ContextMenu>
 27:         </TextBox> 
 28:     </Grid>

Now one can change the three SolidColorBrush in resources to change color of the icon on the context menu. Here I have shown three differently themed icons of the context menu.

  1:    <UserControl.Resources>
  2:         <SolidColorBrush x:Name="MenuTickBorderColor" Color="Blue"/>
  3:         <SolidColorBrush x:Name="MenuTickFillColor" Color="LightBlue"/>
  4:         <SolidColorBrush x:Name="MenuTickFontColor" Color="Green"/>
  5:     </UserControl.Resources>

image

  1:     <UserControl.Resources>
  2:         <SolidColorBrush x:Name="MenuTickBorderColor" Color="Red"/>
  3:         <SolidColorBrush x:Name="MenuTickFillColor" Color="LightPink"/>
  4:         <SolidColorBrush x:Name="MenuTickFontColor" Color="Red"/>
  5:     </UserControl.Resources>

image

  1:    <UserControl.Resources>
  2:         <SolidColorBrush x:Name="MenuTickBorderColor" Color="Brown"/>
  3:         <SolidColorBrush x:Name="MenuTickFillColor" Color="Yellow"/>
  4:         <SolidColorBrush x:Name="MenuTickFontColor" Color="Brown"/>
  5:     </UserControl.Resources>

image

The above technique might not be suitable for every scenario and using images might be more easy. I am not a big fan of writing code in backend rather I prefer to follow MVVM pattern where ever possible, In future post I will write about how to connect context menu using the view model