ContextMenu inside ContextMenu in WPF - c#

I'm trying to get the following behavior:
When I right-click on My button it should open a window with buttons. When I right-click Button 1.2, I want to open another window with another kind of buttons.
NOTE: The style of Button 2.x is different than on the Button 1.x,
I've tried to make this work using ContextMenus, but when I right click on Button 1.x nothing happens. Is it impossible to use nested ContextMenus? Are there any other possibilities?
Here is an example:
<Button Content="Hello">
<Button.ContextMenu>
<ContextMenu>
<MenuItem/>
<ContextMenu.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Template">
<Setter.Value>
<ControlTemplate>
<Button Content="Level 1">
<Button.ContextMenu>
<ContextMenu>
<MenuItem />
<ContextMenu.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Template">
<Setter.Value>
<ControlTemplate>
<Button Content="Level 2" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
</Button>

Much easier to use nested MenuItems
<Button Content="Hello">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Level1">
<MenuItem Header="Level2">
<MenuItem Header="Level3"></MenuItem>
</MenuItem>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>

Related

Context Menu Item for ListBox in WPF

I want to display ContextMenu on right click of ListBoxItems in WPF. I tried below code, but ContextMenu is displaying where ListBoxItems are not there also. What I want is to display ContextMenu only on the right click of only ListBoxItems.
<Grid>
<ListBox x:Name="listofConnectedItems" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding MyItems}" MouseRightButtonDown="listofConnectedItems_MouseRightButtonDown" ContextMenuOpening="listofConnectedItems_ContextMenuOpening" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="10">
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="_Start" Click="MenuItemStart_Click" />
<MenuItem Header="Sto_p" Click="MenuItemStop_Click" />
<MenuItem Header="_Clear" Click="MenuItemClear_Click" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
`
Here I attached the screenshot.
Can anybody Please get me through this. Thanks in advance
It should be in IntemContainerStyle:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Open" />
<MenuItem Header="Edit" Command="Binding
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
I think the problem is that You didn't specified height and width of list box so it automaticaly scales to the window size. So technically Your code is working correctly but listbox is everywhere.
try with something like
<ListBox x:Name="listofConnectedItems" Grid.Column="0" Grid.Row="0" BorderThickness="5" Width="200" Height="200"...
and then rightclick outside the listbox

WPF "static" binding in a List

I have a problem with a binding in a List.
I have a List of objects. This List is bound to a ListBox. Of every object in my List I can open a ContextMenu:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding FirstEnabled}"/>
<MenuItem Header="Second" IsEnabled="{Binding SecondEnable}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
In the code like this my objects in the list having the two booleans to bind. Now I want to bind this two booleans not to the objects. I want to bind it "static" to my DataContext. This is not working like this and I have no idea how to realize it.
I googled a lot but found nothing helpful ...
Thanks for helping!
Since, ContextMenu applies to ListBoxItem it will have its DataContext value and ListBoxItem will be its PlacementTarget. So if you want to bind to property of ListBox.DataContext you need to pass current ListBox.DataContext as, for example, Tag to ListBoxItem and then you need to refer to it from ContextMenu via its PlacementTarget. It's all because ContextMenu uses Popup which creates its own visual tree so simple RelativeSource/ElementName binding won't work
<Style TargetType="ListBoxItem">
<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=DataContext}"/>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.FirstEnabled}"/>
<MenuItem Header="Second" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.SecondEnable}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
You can reference every datacontext with the ElementName Syntax:
<ListBox x:Name="myListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding Path=DataContext.FirstEnabled, ElementName=myListBox}"/>
<MenuItem Header="Second" IsEnabled="{Binding Path=DataContext.SecondEnable, ElementName=myListBox}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
With this syntax you use the DataContext of your ListBox and not from the ListItem.

Connect handler to ContextMenu in "Style" section

I need to create structure of ContextMenu in runtime, because existence of MenuItem's of the menu is based on many factors. And I try add handler to ContextMenuOpening event this way:
XAML
<TreeView x:Name="ArticlesTreeView" Grid.Column="0" AllowDrop="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenuService.ShowOnDisabled" Value="True" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Opened="ContextMenu_OnOpened">
<MenuItem Header="First item"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
This code throws XamlParseException on <ContextMenu Opened="ContextMenu_OnOpened"> line. Can I solve issue in another way?
UPD I find that to me it is necessary not ContextMenuOpening and Opened event. I corrected upper code.
Try creating your ContextMenu on your ItemTemplate of the treeview. Try the below code (it is not complete but i hope you get the idea)
<TreeView .....>
<TreeView.ItemTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.ContextMenu>
<ContextMenu ContextMenuOpening="ContextMenu_OnContextMenuOpening">
<MenuItem Header="First item"></MenuItem>
</ContextMenu>
</ContentControl.ContextMenu>
---------Your Item Template here
</ContentControl>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Your question is already answered here.
Placing event handlers in event setter did the work.
<TreeView x:Name="ArticlesTreeView" AllowDrop="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenuService.ShowOnDisabled" Value="True" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First item">
<MenuItem.Style>
<Style TargetType="MenuItem">
<EventSetter Event="Click" Handler="ContextMenu_ContextMenuOpening_1"></EventSetter>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeViewItem>
</TreeViewItem>
</TreeView>
Also change your code behind event handler as
private void ContextMenu_ContextMenuOpening_1(object sender, RoutedEventArgs e)
{
}

Menu item won't show context menu

I have a button that when clicked, displays a ContextMenu. In this ContextMenu, I have MenuItems. If the MenuItem is left clicked, it should execute a command. All this behavior works properly as of now with the following code:
<Button.ContextMenu>
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding StartContextMenuCommand}" />
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}, Path=Header}" />
</Style>
</ContextMenu.ItemContainerStyle>
<MenuItem Header="{x:Static Name:ContextMenuStartNames.1}"/>
<MenuItem Header="{x:Static Name:ContextMenuStartNames.2}"/>
<MenuItem Header="{x:Static Name:ContextMenuStartNames.3}"/>
<MenuItem Header="{x:Static Name:ContextMenuStartNames.4}"/>
</ContextMenu>
</Button.ContextMenu>
Now I want each menu item to have a context menu with one MenuItem. Since left clicking invokes a Command on a MenuItem, I want the right click behavior to display the following ContextMenu:
<ContextMenu>
<MenuItem Header="Set Default"></MenuItem>
</ContextMenu>
I tried putting this as a setter in the ItemContainerStyle. I also tried putting it as a ContextMenu of a MenuItem, but neither of my attempts, among others have worked. I'm sure I could come up with a hacky way to do this, but I want to keep it clean and simple.
Maybe i do not understand your question (my english is not... anything special):D But this should work if you just want multilevel contextmenu:
<ContextMenu>
<MenuItem Header="Top Level 1">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
<MenuItem Header="Top Level 2">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
</ContextMenu>
Here's my current fix to this issue, but I don't like it at all. I would like to avoid code behind as much as possible.
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding StartCommand}" />
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}, Path=Header}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu StaysOpen="True">
<MenuItem Header="Set As Default"/>
</ContextMenu>
</Setter.Value>
</Setter>
<EventSetter Event="PreviewMouseRightButtonUp" Handler="MenuItem_Click"/>
</Style>
</ContextMenu.ItemContainerStyle>
And the code behind:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
ButtonContextMenu.StaysOpen = true;
(sender as MenuItem).ContextMenu.IsOpen = true;
}

How do I style a submenu of a ContextMenu in wpf

I can style the contextmenu (.style) containing the items and I can style the menu items fine (.ItemTemplate). But how do I style the submenu that pops out when a menuitem has menuitems?
Like:
<ContextMenu>
<MenuItem Header="Font Style">
<MenuItem Header="Under Line" IsCheckable="true"/>
<MenuItem Header="Italic" IsCheckable="true"/>
<MenuItem Header="Bold" IsCheckable="true"/>
</MenuItem>
</ContextMenu>
<ContextMenu>
<ContextMenu.Resources>
<Style x:Key="submenuStyle" TargetType="{x:Type MenuItem}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ContextMenu.Resources>
<MenuItem Header="Font Style">
<MenuItem Style="{StaticResource submenuStyle}" Header="Under Line" IsCheckable="true"/>
<MenuItem Style="{StaticResource submenuStyle}" Header="Italic" IsCheckable="true"/>
<MenuItem Style="{StaticResource submenuStyle}" Header="Bold" IsCheckable="true"/>
</MenuItem>
</ContextMenu>
FROM Aran Mulholland's answer:
I think this is your answer. Because the submenu IS a MenuItem, just apply the style to the submenu...
<ContextMenu>
<MenuItem Head="Font Style" Style="{StaticResource submenuStyle}" ...>
<MenuItem ... />
<MenuItem ... />
</MenuItem />
</ContextMenu>

Categories