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

Creating Menus (with Drop-Down Sub-Menus) using Images in WPF

0.00/5 (No votes)
29 Nov 2012 1  
Creating Menus (with Drop-Down Sub-Menus) using Images in WPF.

Introduction

I spent a few days scouring the tech articles trying to make WPF act like WinForms in respect to creating a ToolTip style menu, including images and drop-down menus. I found a lot of hacks, but deep down I just knew that the WPF developers had to have implemented some slick XAML method for creating menus that involved relative referencing of images and vertical drop-down menus that weren’t hacked-together WinForm throwbacks.

I was right.

However, I have yet to find a definitive reference. So I’m creating one. Hopefully this helps someone out there so that you don’t go through the few days of trial-and-error that I went through!

First step: Repeat after me: WPF is not WinForms. Repeat that about 100 times. Remove everything you know about embedded resources from your mind. Also, erase all knowledge of ToolTip driven menus. Ok… now that we have that out of the way, time to rebuild that knowledge from a WPF worldview.

Tutorial

First, go create a WPF test project (or use your own, because we all know that we all hate it when someone says, "Let’s do this in a test project!" because really, you just want it to work in your current project). This will work whether you are using a UserControl or a Window. It will work whether you are compiling as a DLL or an EXE. I promise. I’ve tested it. And all the code below works ... because I’ve compiled it, run it and tested it. I pinky-promise that one… because my biggest pet-peeve with technet articles is code that you know never saw the inside of the compiler.

  1. In your XAML, add a DataContext directive to bind relative to self:
<Window x:Class="VisualMenus.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350" Width="525"
DataContext="{Binding
RelativeSource={RelativeSource Self}}">

Setting this property guarantees that you will bind to the resources relative to the current data context (i.e., it won’t reach back to a parent, out to a child, or off into the cloud… or any other such nonsense… lord knows you wouldn’t want to bind to your Facebook photos by accident.

  1. Add your images. If you’re going to be using boring text menus, skip this step. But then again, if you’re reading this tutorial, you’re not going to want to skip this step!
  • Add a folder to your project called Images, or Resources, or Foo… it really doesn’t matter.

  • Add your images to your new folder. Easiest way to do this is to go and copy them into the folder that was just created in Windows Explorer, and then suck them into the project as existing files.

  • Now, and this is REALLY important. For each and every file, make sure that the Build Action for the image is set to "Resource", and Copy to Output Directory is set to "Do Not Copy." This is the new-and-improved way to define resources in WPF. You don’t need to add them directly to your build preferences, and you don’t have to generate a RESX file (remember, I said to forget all that!!) (I know, I’m the one who just brought it up… I can’t help it… I’ve been trained over so many years… progress, not perfection, right?)

  1. Now, the fun part ... create your visual menu.
  • Go back to your XAML for your Window or User Control. Create a Menu. You can drag and drop the control from your toolbox, or you can just type it out. I prefer the latter ... old school, I guess.
  • Pretty, huh? Ok, now we get to add the fun stuff. First, define a MenuItem.Icon tag for one of your menu items.

  • Now, still in your XAML, go create a section called <Window.Resources> above your <Grid>… or in the case of a UserControl, you’re going to create a section called <UserControl.Resources> and place it before your DockPanel, Grid or whatever other top visual element exists in your XAML file. Add a <BitmapImage> resource definition for the image you want to tie to your MenuItem. And then tie it to your MenuItem in the Image tag. Check out the example.

You will notice I added a couple of extra "prettification" tags ... alignment, height, width, etc. All of that is all you… go ahead and make the visuals appear how you want them.

And this is what it looks like on the preview window. I love preview windows… just sayin’.

At this point, I’m going to run the app to show what this menu looks like running, and to show that the image does, in fact, appear as expected. Check it out!! It works!! (If you’ve just come across this tutorial after a couple days of trying to get this to work, you’ll understand my exuberant gleefulness.)

And look here ... the images are showing up, but not copied to the bin directory:

  • Ok, now it’s time to wire up the rest of ‘em and move on to the drop-down portion of this fun, exciting happiness. Under your <Window.Resources> (or <UserControl. Resources>) section, add a reference for each image you want to add to your menu, then tie each reference to your menu by adding MenuItem Icon Images and reference by Resource Key. Make sure each resource image has a unique Key!!

Let’s test again, shall we?

  1. At this point, I’m going to go ahead and wire up some event handlers.
  • Menus are nothing if they don’t actually do something, right? I’ve found the fastest way to do this is to go to each MenuItem, type in Click="" and IntelliSense will pop up the option for you to create a New Event Handler by double-clicking the alert. You can rename the handlers later, if you so choose.

And here’s the code-behind. I know… this is painfully obvious… but it might not be to some people. Don’t judge!

  1. And now for those drop-down menus. You know the ones… the ones that were easy to create using WinForms, but seem to be totally elusive in WPF? Yes, those. They’re not as hard as you think. Go back to the XAML, and under add the following code under one of your menu items:
<MenuItem.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
Orientation="Vertical"/>
</ItemsPanelTemplate>
</MenuItem.ItemsPanel>

Now, add menu items under that block of code and give them event handlers, too. Yes, it is THAT easy.

And ... the code-behind:

Wire up what you want it to do, and you’re done!!

And yes, you can add images to those drop-down menu items the same exact way you did above, and they appear nicely to the left of the text. And because I pinky-promised, here’s the complete code running:

Have fun with this, and happy coding!!

Points of Interest

The one thing I learned during this exercise is that ... if you're going to write a code tutorial... try not to make assumptions! When you say something like "Change the Build Action to Resource" it would be exceedingly helpful to call out exactly WHERE to make that change. Everything in the project has a Build Action associated with it. And if you're reading a code tutorial (even mine) and something is unclear ... ask for clarification, because ... the rest of the world reading it is likewise wondering what was going through the author's mind when he or she was writing.

History

First draft

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