1

I have a WPF submenu that I want to reuse in a few places in my XAML. It's a collection of eight <MenuItem> elements with some complicated bindings that I don't want to copy/paste. However, the holder is different in each case: in one place the parent is a <Menu>, in another place the parent is a <MenuItem> in a <ContextMenu>.

I've been experimenting with <Setter Property="Items"> in my <Style> but I think maybe I'm on the wrong track.

To make it concrete, I'm trying to reduce the code duplication from something like this:

<Menu>
    <MenuItem Header="Details"    IsCheckable="True" ... />
    <MenuItem Header="List"       IsCheckable="True" ... />
    <MenuItem Header="Thumbnails" IsCheckable="True" ... />
    ...
</Menu>
...
<ContextMenu>
    <MenuItem Header="View">
        <MenuItem Header="Details"    IsCheckable="True" ... />
        <MenuItem Header="List"       IsCheckable="True" ... />
        <MenuItem Header="Thumbnails" IsCheckable="True" ... />
        ...
    </MenuItem>
</ContextMenu>
Chris Dolan
  • 8,905
  • 2
  • 35
  • 73

1 Answers1

2

How about something like this:

You'll need to create the following collection in your resource dictionary:

<Collections:ArrayList x:Key="MenuItems" x:Shared="false">
    <MenuItem Header="Details" />
    <MenuItem Header="List" />
    <MenuItem Header="Thumbnails" />
</Collections:ArrayList>

You'll need to add the following namespace:

xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"

...

And then just use the collection:

<Menu ItemsSource="{StaticResource MenuItems}" />

...

<ContextMenu>
    <MenuItem Header="View" ItemsSource="{StaticResource MenuItems}" />
</ContextMenu>
dzavala
  • 988
  • 10
  • 21
  • Aha, that sounds great. However, it breaks all of my IsChecked="{Binding ElementName=...,Path=...}" constructs in the repeated MenuItems – Chris Dolan Nov 29 '12 at 17:23
  • Could you post the whole binding expression? It'd be easier knowing what the differences are between the bindings on each menu. – dzavala Nov 29 '12 at 17:28
  • Here's one. The others are very similar. "thisControl" is the enclosing user control. – Chris Dolan Nov 29 '12 at 17:41
  • To clarify: the localization binding is working fine. But the IsChecked binding stopped working when I switched to the ArrayList approach. Thanks much – Chris Dolan Nov 29 '12 at 17:43
  • 2
    I would expect the bindings to work for the first case (plain Menu control), but not for the second (ContextMenu) because ContextMenu is not part of the same visual tree. Take a look at these questions. The first approach worked for me, but if you rather not change the code behind, then try the second link. http://stackoverflow.com/questions/1013558/elementname-binding-from-menuitem-in-contextmenu http://stackoverflow.com/questions/2617122/wpf-menuitem-command-binding-to-elementname-results-to-system-windows-data-error – dzavala Nov 30 '12 at 11:57
  • Excellent. I had to do the following, but it worked. `foreach (object item in Resources["MenuItems"] as ArrayList) NameScope.SetNameScope(item as DependencyObject, NameScope.GetNameScope(this));` – Chris Dolan Nov 30 '12 at 15:59
  • Oh, also: I had to change x:Shared to true because otherwise the newly instantiated MenuItems lost their NameScope. – Chris Dolan Nov 30 '12 at 16:01
  • Nope, I take it back. x:Shared=true broke everything. I'm back to square one... I can't get the namescope to stick. – Chris Dolan Nov 30 '12 at 16:19