WPF - Create Context Menu mixing static and dynamic items - c#

I try to create Context Menu mixing static and dynamic items.
this is the code:
<CollectionViewSource x:Key="DynamicMenuBridge" Source="{Binding Path=MyMenuCollection}" />
<ContextMenu x:Key="_Menu" >
<ContextMenu.ItemsSource>
<CompositeCollection>
<MenuItem Header="A" Click="..."/>
<Separator/>
<CollectionContainer Collection="{Binding Source={StaticResource DynamicMenuBridge}}" >
</CollectionContainer>
<Separator/>
<MenuItem Header="b" Click ="..."/>
<MenuItem Header="c" Click="..."/>
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
But it does not work, why ?
(in debuging by snoop. it looks like that the CollectionContainer does not exist)

Related

ContextMenu and Hierachicaldatatemplate Binding

In the MainWindow I have an ObservableCollection of "parent" items.
Every parent, has an ObservableCollection of "device" items.
The first level of my ContextMenu is properly bind to the items of the first Collection. The problem is, for every MenuItem I am getting always the same results (meaning that the datacontext for each MenuItem is always the same "parent"?)
Here is a screenshot, to better understand:
ContextMenu
And here is the XAML code:
<StackPanel.Resources>
<CollectionViewSource Source="{Binding Parents}" x:Key="Parents"/>
<HierarchicalDataTemplate DataType="{x:Type local:parent}">
<HierarchicalDataTemplate.ItemsSource>
<Binding>
<Binding.Source>
<CompositeCollection>
<MenuItem Header="ParentStartAll"/>
<MenuItem Header="ParentStopAll"/>
<MenuItem Header="ParentRestartAll"/>
<Separator/>
<CollectionContainer Collection="{Binding Childs, Source={StaticResource Parents}}"/>
</CompositeCollection>
</Binding.Source>
</Binding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:device}">
<HierarchicalDataTemplate.ItemsSource>
<Binding>
<Binding.Source>
<CompositeCollection>
<MenuItem Header="StartAll"/>
<MenuItem Header="StopAll"/>
<MenuItem Header="RestartAll"/>
<Separator/>
<CollectionContainer Collection="{Binding Processes, Source={StaticResource Parents}}"/>
</CompositeCollection>
</Binding.Source>
</Binding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
[...]
</StackPanel.Resources>
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" ItemsSource="{Binding Parents}">
</ContextMenu>
</StackPanel.ContextMenu>
What am I doing wrong? Also, when I try to open the ContextMenu for the second time, it only shows the first level (only the "parents").
Any hints?
Pretty newbie here, so please don't angry if the question is too easy or if I made some ugly mistakes. I have to say it was not easy to manage the binding in the firstplace and I am struggling to get this contextmenu working.
Thanks a lot.

Dynamically binding and statically adding MenuItems - using view Models/MVVM

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>

WPF, TreeViewItem, how to not show contextMenu according to dependency property?

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 !

In Button Click Context Menu How do I bind to viewModel?

I have a button on click on that button opening a context menu, now clicking on the context menus is to be binded to viewModel. But its not happening.
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding Path=Parent.PlacementTarget.Tag.CopyViewCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>
I have tried the tag property but it seems to me that its not working. The viewmodel is working fine if I bind to the button itself, but the contextMenu dataBinding is not working.
EDIT:
Now as the code is working after discussion, I think to post it here.
What the changes I made is I put UpdateSourceTrigger="Propertychanged" here is the code
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu Width="{Binding RelativeSource={RelativeSource Self}}">
<MenuItem Header="Copy View link " Command="{Binding CopyViewCommand, UpdateSourceTrigger=PropertyChanged}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>
However I don't know how come suddenly it works, it has to work with tag property in case of Button Context menu. If anybody put some light into this I think many people like me who are new WPF and data binding will be benefited.
I'm assuming you are using this Button inside the UserControl. Please try below code
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CopyViewCommand}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>
<Button Content="Copy" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding Path=CopyViewCommand}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
CopyViewCommand Bound directly from your DataContext... which is your ViewModel..
You have to setyour ContextMenu's DataContext to your ViewModel. One way to do this is by having an Opened eventhandler for the context menu.
Take a look at my answer in the below link -
Context Menu items command binding WPF using MVVM

How do I reuse item children via a style in XAML?

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>

Categories