How do I style a submenu of a ContextMenu in wpf - c#

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>

Related

WPF : Remove context menu items based on condition

I have a context menu in WPF with following items:
<ContextMenu x:Key="MyContextMenu">
<MenuItem Header="{x:Static localization:Resources.MyContext_Command1}" Command="{Binding Command1}" />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command2}" Command="{Binding Command2}" />
<Separator />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command3}" Command="{Binding Command3}" Visibility="{Binding IsItemActive, Converter={converters:BooleanToVisibilityConverter}}" />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command4}" Command="{Binding Command4}" Visibility="{Binding IsItemActive, Converter={converters:BooleanToVisibilityConverter}}" />
<Separator Visibility="{Binding IsItemActive, Converter={converters:BooleanToVisibilityConverter}}"/>
</ContextMenu>
With the above code these menu items(Command3 and Command4) are appearing grey(Disabled) when IsItemActive = false and appear black(Enabled) when IsItemActive = true. But i want my Menuitems(Command3 and Command4) and also Seperator to Disappear / Appear from context menu based on "IsItemActive".How can i achieve this ?
This should do the trick. But I cannot get my bindings to work now so it's not tested. You will have to give a name to the element that you are applying this in order to make the binding work. For my case, it's a window.
Create a dependency property for IsItemActive only then you can bind.
Tip : type propdp and double tab in Visual Studio to use code snippet.
<Window x:Class.....
x:Name="mainwindow"
...>
Then in the <Window.Resources> define the styles
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=mainwindow,Path=IsItemActive}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=mainwindow,Path=IsItemActive}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
Duplicate the style and change TargetType="Separator" Then apply the style on your context menu items and separator.
<ContextMenu x:Key="MyContextMenu">
<MenuItem Header="{x:Static localization:Resources.MyContext_Command1}" Command="{Binding Command1}" />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command2}" Command="{Binding Command2}" />
<Separator />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command3}" Command="{Binding Command3}" Style="{StaticResource MenuItemStyle}" />
<MenuItem Header="{x:Static localization:Resources.MyContext_Command4}" Command="{Binding Command4}" Style="{StaticResource MenuItemStyle}" />
<Separator Style="{StaticResource SeparatorStyle}"/>
</ContextMenu>

Flyout c# using mahapps

Hello I am currently using library Mahapps but I have some problems. How can I pop out the flyout when clicking the "Menu 1" MenuItem? I tried with the following code but it did not work.
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="FlyoutOverview" Header="Menu 1" IsCheckable="True" Click="flyoutOverview">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="GlobeWire"/>
</MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem Header="Menu 2"/>
<Separator/>
<MenuItem Header="Menu 3">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="People"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu 4">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="UserDelete"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu 5">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="ControlResume"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
If you have followed the tutorial links I provided then I suppose you are able to create a simple View and its ViewModel.
The View can be a Window and has its Grid content like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Controls:FlyoutsControl Grid.Column="1">
<Controls:Flyout x:Name="yourMahAppFlyout" Header="Flyout" Background="AliceBlue" Position="Right" Width="350"
IsOpen="{Binding ElementName=FlyoutOverview, Path=IsChecked}">
<TextBlock Text="My Flyout is here" />
</Controls:Flyout>
</Controls:FlyoutsControl>
<ListBox Grid.Row="0" Grid.Column="0" ItemsSource="{Binding NameList}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="FlyoutOverview" Header="Menu 1" IsCheckable="True"
IsChecked="{Binding IsMenuItem1Checked}">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="GlobeWire"/>
</MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem Header="Menu 2"/>
<Separator/>
<MenuItem Header="Menu 3">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="People"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu 4">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="UserDelete"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu 5">
<MenuItem.Icon>
<iconPacks:PackIconModern Kind="ControlResume"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
The ViewModel can have these properties:
public MainWindowViewModel()
{
NameList = new ObservableCollection<string>()
{
"John", "Micheal", "Jack"
};
}
public ObservableCollection<string> NameList { get; set; }
public bool IsMenuItem1Checked
{
get { return _isMenuItem1Checked; }
set { SetProperty(ref _isMenuItem1Checked, value); }
}
The first menu item in the listbox binds its "IsChecked" property to "IsMenuItem1Checked" in ViewModel, and FlyOut "IsOpen" property binds to "IsChecked" of that menu item.

ContextMenu inside ContextMenu in WPF

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>

Sub-context menu for WPF

I want to create sub-contextmenu for Filters in my datagrid. How can I do that? Here is my code:
<DataGrid x:Name="DataGridSuppliers" Margin="10" ItemsSource="{Binding}" IsReadOnly="True" >
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Create Supplier" Click="btnCreateSupplier_Click" />
<MenuItem Header="Edit Supplier" Click="btnEditSupplier_Click" />
<MenuItem Header="Filters" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
Create nested sub menuItems inside Filters, that's all what you want:
<ContextMenu>
<MenuItem Header="Create Supplier" Click="btnCreateSupplier_Click"/>
<MenuItem Header="Edit Supplier" Click="btnEditSupplier_Click"/>
<MenuItem Header="Filters">
<MenuItem Header="Sub Filter 1"/>
<MenuItem Header="Sub Filter 2"/>
<MenuItem Header="Sub Filter 3"/>
</MenuItem>
</ContextMenu>

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;
}

Categories