Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamically Generating Context Menu Items

0.00/5 (No votes)
28 May 2014 2  
Article describes how to dynamically generate Context Menu Items, requiring separate templates based on items on the collection

Introduction

Recently I needed to auto generate context menu items bound to command collection in my View Model. and the data template needed to be different based on the type of the item in the list. Article is outcome of what I learned from it.

Background

From the title it sounds like a 30-second task where all you need is to have a collection with different command items and bind it to context menu's ItemsSoruce and use ItemTemplateSelector. I started with the same assumption but solution turned out to be a bit more trickier.

Using the code

Well solution is straight forward. All you need it to remember to use ItemContainerTemplateSelector. But that is not all, you will also need to set property UsesItemContainerTemplate in order for your template selector to be effective.

A very basic example to illustrate is attached:
In the example, ContextMenu is bound to property ContextItems

   <ContextMenu ItemsSource="{Binding Path=ContextItems}" UsesItemContainerTemplate="True"  ItemContainerTemplateSelector="{StaticResource _templateSelector}" /> 

ContextItems is collection of ICommandItem which contains properties like Text (header), ToolTip and Command.

       ContextItems = new List<ICommandItem>(){         
         new SimpleCommandItem() { Text ="Simple Command 1", ToolTip="Simple Tooltip 1"},
         new SeparatorCommandItem(),
         new SimpleCommandItem() { Text ="Simple Command 2", ToolTip="Simple Tooltip 2"} 

SimpleCommandItem class is implementation for the interface.
SeparatorCommandItem implements the interface explicitly but throws exceptions on implementation (for obvious reasons!).

ContextMenuResources.xaml is resource dictionary that holds data templates for both the classes.

SimpleCommandItem Template:

    <DataTemplate x:Key="SimpleCommandItem" DataType="local:SimpleCommandItem">
        <MenuItem Header="{Binding Path=Text}" ToolTip="{Binding Path=ToolTip}" Command="{Binding Command}" />
    </DataTemplate>

And the separator Template:

    <DataTemplate x:Key="SeparatorCommandItem" DataType="local:SeparatorCommandItem">
        <Separator />
    </DataTemplate>  
All that is left to do is to implement ContextMenuItemContainerTemplateSelector
    public class ContextMenuItemContainerTemplateSelector : ItemContainerTemplateSelector 
    {
        private static ResourceDictionary _dictionary;
        static ContextMenuItemContainerTemplateSelector()
        {
            _dictionary = new ResourceDictionary();
            _dictionary.Source = new Uri(@"pack://application:,,,/ContextMenu.Framework;component/ContextMenuResources.xaml");
        }
        public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
        {
            var name = item == null ? null : item.GetType().Name;
            if (name != null && _dictionary.Contains(name))
            {
                return (DataTemplate)_dictionary[name];
            }
            return null;
        }
    } 
History

Keep a running update of any changes or improvements you've made here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here