XAML and Binding Submenu items in a ContextMenu? - wpf

I have a ContextMenu defined on a Datagrid but want to bind submenu items to a collection on my viewmodel. Can anybody suggest how this should be done?
The following is a simple example of what I'm trying to achieve, BUT I want "Test1", "Test2" to come from a collection on my viewmodel, not hardcoded. I know how to bind my collection to the whole ContextMenu, but not how to bind it to just the one submenu...
<ContextMenu>
<MenuItem Header="Add to">
<MenuItem Header="Test1" />
<MenuItem Header="Test2" />
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>
I'm using 3.5 SP1 and the WPF Toolkit.

Guess I should have experimented more. Turns out this was relatively simple:
<my:DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Add to" ItemsSource="{Binding MyItems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem CommandTarget="{Binding}" Click="AddClick">
<MenuItem.Header>
<TextBlock>
<TextBlock.Text><Binding StringFormat="Add to {0}" /></TextBlock.Text>
</TextBlock>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>
</my:DataGrid.ContextMenu>

There is a bug when using MenuItem.ItemTemplate. The color when do mouse over on the sub menu make user misunderstand that they can click to select the menu but it doesn't work for all area even if it's highlighted. See the picture
Then I used this code instead and it worked fine for me.
<ContextMenu>
<MenuItem Header="Add to" ItemsSource="{Binding MyItems}"
DisplayMemberPath="{Binding ItemName}">
<MenuItem.ItemContainerStyle>
<Style>
<EventSetter Event="MenuItem.Click" Handler="Menu_Click"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>

Related

wpf extend contextmenu of textbox

I am searching for a way to extend the contextmenu of a textbox. I know there are dozens of solutions out there that recreate the contextmenu as a whole, but how on earth can I simply add one custom entry to a existing context menu?
Thanks
Klaus
<TextBox>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Cut" />
<MenuItem Command="ApplicationCommands.Copy" />
<MenuItem Command="ApplicationCommands.Paste" />
<MenuItem Command="ApplicationCommands.SelectAll" />
//Your own item here
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
Please not that all command are automatically operation and will work as expected

How can I take different MenuItem controls and use them in one ContextMenu?

For example, I have a simple control below in xaml:
<ContextMenu>
<MenuItem Header = "Open in new tab"/>
<MenuItem Header = "Open in new window"/>
<MenuItem Header = "Open in incognito window"/>
<Separator Padding="0"/>
<MenuItem Header = "Edit..."/>
<Separator Padding="0"/>
<MenuItem Header = "Cut"/>
<MenuItem Header = "Copy"/>
<MenuItem Header = "Paste"/>
<Separator Padding="0"/>
<MenuItem Header = "Delete"/>
</ContextMenu>
Which produces:
I want the Cut/Copy/Paste MenuItem elements to sit in their own control. However, Wpf restricts me from just declaring 3 MenuItems in a control without a parent element. So I tried putting the MenuItems in a Menu, Grid, ItemsControl, and other controls with no luck. The formatting was weird. All i want to do is abstract the Cut/Copy/Paste into a seperate control, and have the end product look identical to the xaml above. Here were my failed attempts:
MyContextMenu.xaml:
<ContextMenu>
<MenuItem Header = "Open in new tab"/>
<MenuItem Header = "Open in new window"/>
<MenuItem Header = "Open in incognito window"/>
<Separator Padding="0"/>
<MenuItem Header = "Edit..."/>
<Separator Padding="0"/>
<ref:MyCutCopyPaste/>
<Separator Padding="0"/>
<MenuItem Header = "Delete"/>
</ContextMenu>
MyCutCopyPaste.xaml:
<Grid>
<MenuItem Header = "Cut"/>
<MenuItem Header = "Copy"/>
<MenuItem Header = "Paste"/>
<Grid>
I can probably take my solution and play around with formatting, but there has to be an easy solution that I'm oblivious too. I know I can also declare each Menu Item (Cut, Copy, and Paste) into it's own xaml file. But I'd like to keep all three in one file, if possible.
You can define those MenuItems as resources and use it in the contextmenu. Refer the below code.
<StackPanel>
<StackPanel.Resources>
<MenuItem x:Key="Cut" Header="Cut" x:Shared="false"/>
<MenuItem x:Key="Copy" Header="Copy" x:Shared="false"/>
<MenuItem x:Key="Paste" Header="Paste" x:Shared="false"/>
</StackPanel.Resources>
<Button Content="Button 1">
<Button.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="Cut"/>
<StaticResourceExtension ResourceKey="Copy"/>
<StaticResourceExtension ResourceKey="Paste"/>
<MenuItem Header="Open in new tab"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
<Button Content="Button 2">
<Button.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="Cut"/>
<StaticResourceExtension ResourceKey="Copy"/>
<StaticResourceExtension ResourceKey="Paste"/>
<MenuItem Header="Open in new window"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>

How to apply a custom style context menu for TextBox (default context menu copy/cut/paste)?

I create style for the MenuItem.
When I create my own menu, everything is good.
But how can I apply a style to the context menu of TextBox?
I mean, the menu (Copy, Cut, Paste, etc.) - I do not want to create new lines, and just change the style.
//My Custom Menu Example
<UserControl.ContextMenu>
<ContextMenu Style="{StaticResource ContextMenuStyle}" HasDropShadow="True">
<MenuItem x:Name="MenuItem1" Header="Open"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
<MenuItem x:Name="MenuItem2" Header="Save"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
<MenuItem x:Name="MenuItem3" Header="Delete"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
You will technically have to to do the same thing you did to your UserControl.ContextMenu to the TextBox.ContextMenu.
Look the below link which has exactly the scenario you are asking about with xaml.

Bind Command for MenuItem in DataTemplate without Tag

I want to bind a command in my ViewModel to a menuItem which is in DataTemplate. I can do that with using Tag. Is there any method which can do the same task but without using tag.
<Window.Resources>
<DataTemplate x:Key="StudentListBoxItemTemplate">
<StackPanel Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}">
<TextBlock Text="{Binding Name}"/>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Trigger" Command="{Binding PlacementTarget.Tag.TriggerCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox
ItemsSource="{Binding StudentList}"
ItemTemplate="{StaticResource StudentListBoxItemTemplate}">
</ListBox>
</StackPanel>
My ViewModel
public class MainViewModel {
public ICommand TriggerCommand { ... }
public ObservableList<Student> StudentList { ... }
}
With your current design, you need to get from the ContextMenu through the StackPanel and back to the DataContext of the containing ListBox. What makes this awkward is that the DataContext of the StackPanel is already narrowed down to a particular student.
There are at least two ways to make this easier:
Provide a TriggerCommand property in Student so the command is right there where you need it
Provide a Parent property in the Student to escape the narrowed scope
You can try to add click event to the menuItem like following
<Menu Style="{StaticResource bellRingersFontStyle}" Height="23" Name="menu1" Width="Auto" DockPanel.Dock="Top" VerticalAlignment="Top">
<MenuItem Header="_File">
<MenuItem Header="_New Member" Name="newMember" Click="newMember_Click" >
<MenuItem.Icon>
<Image Source="Face.bmp" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Save Member Details" Name="saveMember" IsEnabled="False" Click="saveMember_Click">
<MenuItem.Icon>
<Image Source="Note.bmp" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="E_xit" Name="exit" Click="exit_Click" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About Middleshire Bell Ringers" Name="about" Click="about_Click" >
<MenuItem.Icon>
<Image Source="Ring.bmp" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
Try binding the command to Click. My VS is down so can't check at this moment.
One way would be to get the context menu collection presentation defined in your viewmodel, which will contain the header string and command action (maybe with predicate).
The viewmodel creates an observable collection of the contextmenu items and the view binds that to ContextMenu itemssource and sets the displaymember path to header string.

How to add context menu to wpf datagrid?

How does one add a ContextMenu to a DataGrid? I want to be able to right click anywhere on the DataGrid.
<DataGrid>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Click Me" Click="MenuItem_Click" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>

Resources