Click here to Skip to main content
Click here to Skip to main content

ContextMenu in WPF with XML Binding

, 2 Sep 2007
Rate this:
Please Sign up or sign in to vote.
An article on how to create a customizable ContextMenu to use in your application based on an XML data source
Screenshot - Article.gif

Introduction

I want to present to you a part of one of my projects that I considered interesting to use within WPF. I will describe the creation of a customizable ContextMenu to use in your application, based on an XML data source.

Background

The traditional way of creating ContextMenus (it could also be Menu) involved building an Item collection and specifying the properties from the code. Even if you use VS IDE, it is not so easy... you have to manually add each item and open endless dialogs to set all of the properties for each MenuItem. Then changing an item at a later time... it really takes a lot of time.

Using the Code

WPF and XAML make your life a lot easier because they support Binding. As you know, Binding in WPF is really easy and can be done with little code in most cases. Let's return to our ContextMenu. In WPF, you can declare an ItemsSource property and bind it to a data source.

The data source can be of any supported kind, but I think one of the greatest is the XML data source. Building an XML data source is easy, thanks to the XMLDataProvider class. You only need to name the object and specify the external source, as well as the Xpath for the root element, and you're ready to go.

<XmlDataProvider x:Key="dataProvider" XPath="//Menus/Menu[@id='Menu1']"
    Source="file.xml"/>

For the given file.xml:

<Menus xmlns="">
    <Menu id="Menu1"  Name="Main Menu">
        <item>item1</item>
        <item>item2</item>
        <item>item3</item>
    </Menu>
</Menus>

Now let's customize the look of the menu DataTemplate. Basically, now you can create any control you want to hold inside the menu while binding to DataTemplate properties.

<DataTemplate DataType="item">
    <MenuItem Header="{Binding XPath=@Name}">
    </MenuItem>
</DataTemplate>

Here I've used MenuItem, but you can use ANY Control. As you saw earlier (XPath="//Menus/Menu[@id='Menu1']" and XPath=@Name), we've used XPath (XML Path Language). This is a powerful query language for XML that you can use in Binding. In short terms, XPath=@Name selects the attribute Name from the current node and XPath="//Menus/Menu[@id='Menu1']" selects the node of type Menu, which is the child of a root Menu's node and has the "Menu1" ID attribute.

Of course, you can add multiple attributes and nodes to the XML node and further customize the ContextMenu. For example, given the following file.xml...

<Menus xmlns="">
    <Menu id="Menu1"  Name="Main Menu">
        <item Name="Item1" ImageLocation="c:\image1.jpg"></item>
        <item Name="Item2" ImageLocation="c:\image2.jpg"></item>
        <item Name="Item3" ImageLocation="c:\image3.jpg"></item>
    </Menu>
</Menus>

...you can use:

<DataTemplate DataType="item">
    <MenuItem Header="{Binding XPath=@Name}">
        <MenuItem.Icon>
            <Image  Source="{Binding XPath=@ImageLocation}"></Image>
        </MenuItem.Icon>
    </MenuItem>
</DataTemplate>

So, the menu item has an icon whose DataSource is the file specified in the ImageLocation attribute of the item node. So far so good, but we will need submenus to this menu. For example, for the given file.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Menus xmlns="">
    <Menu id="Menu1"  Name="Main Menu">
        <item Name="Item1" ImageLocation="c:\image1.jpg"></item>
        <item Name="Item2" ImageLocation="c:\image2.jpg"></item>
        <item Name="Item3" ImageLocation="c:\image3.jpg"></item>
        <itemlist Name="Submenu">
            <item Name="Item5" ImageLocation="c:\image1.jpg"></item>
            <item Name="Item6" ImageLocation="c:\image2.jpg"></item>
            <item Name="Item7" ImageLocation="c:\image3.jpg"></item>
        </itemlist>
    </Menu>
    <Menu id="Menu2"  Name="Intermediate">
        <item Name="Item8" ImageLocation="c:\image1.jpg">=</item>
    </Menu>
    <Menu Name="Advanced">
        <item Name="Item9" ImageLocation="c:\image1.jpg"></item>
    </Menu>
</Menus>

To enable the itemList to show submenus, you must add these lines of XAML:

<HierarchicalDataTemplate DataType="Menu" ItemsSource="{Binding XPath=*}">
    <TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="itemlist" ItemsSource="{Binding XPath=*}">
    <TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>

Again, I've used TextBlock... You can use any Control you want for your project. Now to add the ContextMenu to your Control:

ContextMenu menu = new ContextMenu();
Binding binding = new Binding();
binding.Source=this.Resources["dataProvider"];
binding.XPath=".";//here you can have an additional XPath expression
            // to filter the data in the dataProvider
menu.SetBinding(Menu.ItemsSourceProperty,binding);
this.ContextMenu = menu;

So now you have a more simplified and ready-to-use ContextMenu that, after being built, is easy to modify. Simply modifying the external XML file will change the ContextMenu.
I hope you found this article useful. I await your questions regarding this article.

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

Share

About the Author

Mihai Mihaila
Software Developer Microsoft
Denmark Denmark
Even if in the past I've worked with Pascal, C++, Java or VB since I started learning C# I've continuously been interested in everything related to .NET Framework.

Comments and Discussions

 
GeneralMy vote of 1 Pinmemberabdul systalent21-Oct-10 5:08 
GeneralEvents PinmemberOrekaria13-Oct-08 20:03 
GeneralSome errors Pinmemberdimzon5-Dec-07 6:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140821.2 | Last Updated 2 Sep 2007
Article Copyright 2007 by Mihai Mihaila
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid