Good day.

I have a similar code:

<ListBox ItemsSource="{Binding}" Style="{StaticResource lbStyle}" > <ListBox.ItemTemplate> <DataTemplate> <local:iEventControl> <local:iEventControl.ContextMenu> <ContextMenu> <MenuItem Header="Открыть таблицу" Command="{Binding MenuItemClick}"/> </ContextMenu> </local:iEventControl.ContextMenu> </local:iEventControl> </DataTemplate> </ListBox.ItemTemplate> </ListBox> 

Is it possible to somehow get the ListBoxItem in the MenuItemClick handler, which has a context menu called? (Well, or the ListBox itself, inside which the menu was called).

Wrote using Command by example, in this case for some reason it does not work (DataContext is installed).

Thank.

  • Are you sure the DataContext installed correctly? Show VM code. - VladD
  • DataContext does not help here. The context menu, as I recall, is not part of the logical tree. You need to use CommandTarget - vitidev
  • @vitidev: Hm. Maybe you are right, now I'll try. - VladD
  • @vitidev: Strange, it works like this for me: pastebin.com/3caJsE1x . Perhaps they pull out a DataContext? - VladD
  • @VladD you have a context menu control. there are no problems. in DataTemplate will not work. - vitidev

2 answers 2

If the command is in the list item view model, then nothing needs to be done - the binding works correctly. MenuItemClick will be called in the class for which the list item is drawn.

If the command handler is in the view model that contains the list itself, then it’s impossible to point to the right place due to the fact that the context menu is not part of the logical tree and RelativeSource does not work.

To indicate the correct command, use various tricks like https://stackoverflow.com/questions/15033522/wpf-contextmenu-woes-how-do-set-the-datacontext-of-the-contextmenu

Instead of dancing with a tambourine, I use the CommandReference class.

 public class CommandReference : Freezable, ICommand { public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof (ICommand), typeof (CommandReference ), new PropertyMetadata( OnCommandChanged)); public ICommand Command { get { return (ICommand) GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var commandReference = d as CommandReference; var oldCommand = e.OldValue as ICommand; var newCommand = e.NewValue as ICommand; if (oldCommand != null) { oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged; } if (newCommand != null) { newCommand.CanExecuteChanged += commandReference.CanExecuteChanged; } } #region Freezable protected override Freezable CreateInstanceCore() { return this; throw new NotImplementedException(); } #endregion #region ICommand Members public bool CanExecute(object parameter) { if (Command != null) return Command.CanExecute(parameter); return false; } public void Execute(object parameter) { Command.Execute(parameter); } public event EventHandler CanExecuteChanged; #endregion } 

Which allows you to set a link to the command in the window / control resources

 <mvvm:CommandReference x:Key="ShowCommandRef" Command="{Binding ShowCommand}" /> 

that is, relative to the DataContext window and call it in the menu

 <MenuItem Command="{StaticResource ShowCommandRef}" CommandParameter="{Binding}" /> 
  • Just a list item? How to organize the execution of the command declared in the VM? - bodynar
  • @bodynar You have an error. It is necessary so <ListBox ItemsSource = "{Binding MyList}" is not a DataContext, but a source list. Then the DataTemplate gets an instance of the contents of the list, and your Command = "{Binding MenuItemClick}" will specify the MenuItemClick command in that instance. It works this way, but it looks like you need a single checker for the list to which the selected item will arrive. - vitidev
  • tooting. Having read the messages above, it also reached this conclusion. How then to organize Command and ItemsSource? - bodynar
  • @bodynar depends on the goals. depending on where the command call should jump - to the class method of the list item or to the class where the list itself is contained. If the first, then it goes there and so (it is worth only correcting the ItemSource) - vitidev
  • It is necessary for me, that the command was caused in ViewModel. You also need to get ListBoxItem, which was called from the context menu. - bodynar

If I understand the question correctly, then you can connect something like this from a VM

  <ListView.Resources> <ContextMenu x:Key="Menu" ItemsSource="{Binding DataContext.Menu, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"/> </ListView.Resources> <ListView.ItemContainerStyle> <Style TargetType="{x:Type ListViewItem}"> <Setter Property="ContextMenu" Value="{StaticResource Menu}"/> ... 

Menu - a collection of commands that is already displayed by style as it should.