I want to use a list of custom objects to generate a list of MenuItems in a menu, but at the bottom of that menu I want a couple of static MenuItems to always appear. Logically in my head, this can be done by programatically creating another list to bind to that always has those MenuItems at the bottom, but this strikes me as a bit of a naive way of approaching this. I'm sure there's a more elegant way to do it with the list I already have along with some XAML wizardry, possibly with some kind of DataTemplate. Any pointers?
Asked
Active
Viewed 469 times
3
-
Nice question! My immediate hunch was to merge the two seamlessly so as to give the visual *experience* of a single menu and do the whole thing in Xaml. I, like you, would avoid code if there's any way around it, and in this case there is. I'll watch the answers here with interest! – Gayot Fow Jul 11 '13 at 17:29
-
Would binding the MenuItems to an ObservableCollection
work for you? You can have the static objects you speak of at the bottom of the list via sorting using the OrderBy method in a linq query. Not sure if this is what you're looking for... – Jul 11 '13 at 17:31 -
Or are you Just talking about combining and sorting the two collections? – Jul 11 '13 at 17:32
-
@Killingsworth That's what I was referring to when I talked about generating a second collection programmatically, and that's the kind of approach I was hoping to avoid. – Abion47 Jul 12 '13 at 01:27
2 Answers
5
Like McGarnagle said, you can use a CompositeCollection. However, you don't need to create a resource for the fixed menu items. You can place them directly in the CompositeCollection like this:
<Menu>
<Menu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Path=MyItems}" />
<Separator/>
<MenuItem Header="Fixed item 1" />
<MenuItem Header="Fixed item 2" />
</CompositeCollection>
</Menu.ItemsSource>
</Menu>

17 of 26
- 27,121
- 13
- 66
- 85
2
Use a CompositeCollection
, with two child collections (the generated menu items, and the static ones).
Edit Should look something like this:
<Button Content="Test">
<Button.Resources>
<viewModel:MenuItemCollection x:Key="FixedMenuItems">
<MenuItem Header="Fixed Item" />
</viewModel:MenuItemCollection>
</Button.Resources>
<Button.ContextMenu>
<ContextMenu>
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{StaticResource FixedMenuItems}" />
<CollectionContainer Collection="{Binding MyMenuItems}" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
</Button.ContextMenu>
</Button>
Where viewModel:MenuItemCollection
is just a list of MenuItem
:
public class MenuItemCollection : ObservableCollection<MenuItem>
{
}
Second Edit
One fix is needed for this. To bind to "MyMenuItems" in the view model, it's necessary to use a proxy as outlined in this answer. So instead of <CollectionContainer Collection="{Binding MyMenuItems}" />
, you would end up using:
<CollectionContainer Collection="{Binding Path=DataContext.MyMenuItems,Source={StaticResource ProxyElement}}" />
And adding the proxy to the top of the view:
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
<UserControl.Resources>
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>

Community
- 1
- 1

McGarnagle
- 101,349
- 31
- 229
- 260
-
1It's worth noting that the only reason for the proxy code is because of the ContextMenu, which is not part of the visual tree. A standard Menu control would not have this problem. – 17 of 26 Jul 11 '13 at 18:35