This question already has answers here:
WPF - How can I create menu and submenus using binding
(3 answers)
Closed 2 years ago.
I can assign them using but how to view all the items present in the Observable collection in a view model?
<Menu Grid.Row="1" Grid.Column="1" Width="100" VerticalAlignment="Center" Background="Gray">
<MenuItem Header="Item Collection">
<MenuItem Header="Item 1"></MenuItem>
<MenuItem Header="Item 2"></MenuItem>
<MenuItem Header="Sub Items">
<MenuItem Header="SubItem 1"></MenuItem>
<MenuItem Header="SubItem 2"></MenuItem>
</MenuItem>
</MenuItem>
</Menu>
View Model contains a simple int type observable collection.
MenuItems have an ItemsSource property.
<Menu>
<MenuItem Header="Item Collection" ItemsSource="{Binding ItemCollection}">
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }"
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</Menu>
See this question for a more complete answer.
Related
I tried to enable Item2 when Item1 is checked and disable it when Item1 is not checked. How to do that with IValueConverter to convert IsChecked property to Boolean and bind it to IsEnabled Property in Item2.
<ContextMenu x:Name="ItemsContxtMenu">
<MenuItem IsCheckable="True" x:Name="Item1" Header="item1 .."/>
<MenuItem x:Name="Item2" Header="item2 .." IsEnabled="{Binding ElementName=Item1, Path=IsChecked"}/>
</ContextMenu>
You don't need converter, write following xaml:
<Menu VerticalAlignment="Top">
<MenuItem Header="Items">
<MenuItem Name="item1" Header="Item #1" IsCheckable="True" />
<MenuItem Name="item2" Header="Item #2" IsEnabled="{Binding ElementName=item1,Path=IsChecked}" />
</MenuItem>
</Menu>
I'm trying to have a dynamic menu item using MVVM from an observable collection. Everything worked, but then I needed to add a "add new" button to the end. I found a solution using a CompositeCollection, like here:
How do I dynamically bind and statically add MenuItems?
So have the following code, where TimeSpans is a collection of ViewModels:
<MenuItem Header="Time Ranges">
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding TimeSpans}" />
<Separator />
<MenuItem Header="Add New" cal:Message.Attach="NewTimeSpan()" />
</CompositeCollection>
</MenuItem.ItemsSource>
<MenuItem.ItemTemplate>
<ItemContainerTemplate>
<MenuItem Header="{Binding Name}" cal:Message.Attach="ConfigureTimeSpan()" />
</ItemContainerTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
However, the view models are not populated like it was just using ItemsSource="{Binding TimeSpans}", it's not showing anything:
I suspect this is because I'm in the StackOverflow answer above the binding is actually a collection of MenuItems, so that composite collection makes sense. Whereas mine's mixing ViewModels & MenuItems.
Is there any way to construct the collection of menu-items created from ViewModels in the XAML so I can bind it?
For anyone else who comes across this, as Szabolcs Dezsi said, I needed to use a resource for the CollectionViewSource (bad reading comprehension on my part, as that was in the answer linked in my question).
Working code below:
<MenuItem Header="Time Ranges" x:Name="TimeRangesMenuItem">
<MenuItem.Resources>
<CollectionViewSource Source="{Binding ElementName=TimeRangesMenuItem, Path=TimeSpans}" x:Key="TimeSpanMenuItems" />
</MenuItem.Resources>
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource TimeSpanMenuItems}}" />
<Separator />
<MenuItem Header="Add New" cal:Message.Attach="NewTimeSpan()" />
</CompositeCollection>
</MenuItem.ItemsSource>
<MenuItem.ItemTemplate>
<ItemContainerTemplate>
<MenuItem Header="{Binding Name}" cal:Message.Attach="ConfigureTimeSpan()" />
</ItemContainerTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
I have a treeview using the following style:
<HierarchicalDataTemplate x:Key="itemTemplate" DataType="{x:Type AttCatalog:AttachmentCatalogModel}" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" Tag="{Binding Guid}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="New Item"/>
<MenuItem Header="Move to..." />
<MenuItem Header="Delete" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
<TreeView x:Name="tree" HorizontalAlignment="Left" Width="216" BorderThickness="0,0,1,0" Background="#FFFBFBFB" IsEnabled="{Binding IsEnabled}" ItemsSource="{Binding Catalogs}" ItemTemplate="{StaticResource itemTemplate}" TreeViewItem.Expanded="OnExpandItemHandler" Margin="0,0,0,241" SelectedItemChanged="tree_SelectedItemChanged">
you can see TextBlock Tag binding a Guid property, my question is, how to do that when this Guid is empty (00000-00000000-00000), not show the contextMenu?
In your context menu, bind the visibility to the Guid, and treat it with a converter =>
<ContextMenu Visibility="{Binding Element=Guid,
Converter={StaticResource GuidToVisibilityConverter}}">
<MenuItem Header="New Item"/>
<MenuItem Header="Move to..." />
<MenuItem Header="Delete" />
</ContextMenu>
In your converter, you can treat your Guid value the way you want, to either return Visibility.Visible or Visibility.Hidden, depending on the value.
You can find more information on converters here.
Hope that helped !
Here My code to bind IsChecked property of menu.
<MenuItem Header="_View">
<MenuItem IsCheckable="True" IsChecked="{Binding ElementName=TermMenu, Path=IsChecked}" Header="Term" />
<MenuItem IsCheckable="True" IsChecked="True" Header="Key" />
<MenuItem IsCheckable="True" IsChecked="True" Header="Hand" />
<MenuItem IsCheckable="True" IsChecked="True" Header="Rule" />
</MenuItem>
Here is the context menu
<ContextMenu x:Key="DataGridColumnHeaderContextMenu" >
<MenuItem x:Name="TermMenu" IsCheckable="True" IsChecked="True" Header="Key Term" />
<MenuItem x:Name="Key" IsCheckable="True" IsChecked="True" Header="Key Term Description" />
<MenuItem x:Name="ShortHand" IsCheckable="True" IsChecked="True" Header="Hand" />
<MenuItem x:Name="Rule" IsCheckable="True" IsChecked="True" Header="Rule" />
</ContextMenu>
Now I want when the context menu item is check the main menu View will be checked automatically. But my code is not working. Please explain me why.
x:Name does not work in resources. the element with the specified name in ElementPath does not exist. this is why the binding doesn't work. you can't access TermMenu from the code behind either. You should bind both to a view-model as #wilford sugested.
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>
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>