Passing ContextMenu source to WPF command

An interesting problem with shooting commands from context menu items ...

I want to run a command to insert a row into my InsertRowCmd control. This command should know where to insert the row.

I could use Mouse.GetPosition (), but as a result I would get the mouse position that would be above the menu item. I want to get the original context menu.

Are there any suggestions on how to pass the start of the context menu as a command parameter?

Code example:

<UserControl x:Name="MyControl">
<!--...-->
        <ContextMenu x:Name="menu">
            <MenuItem Header="Insert Row" Command="{x:Static customCommands:MyCommands.InsertRowCmd}" CommandParameter="?"/>
        </ContextMenu>
</UserControl>

My current ideas are:

-Use the click handler instead to find the source code. The problem is that I then have to handle enable / disable.

-Handle click event . . , .

?

EDIT:

Josh Smith CommandSinkBinding ViewModel. , , , .

+5
3

TranslatePoint, (0, 0) ContextMenu . , CommandParameter ContextMenu :

CommandParameter="{Binding IsOpen, ElementName=_menu, Converter={StaticResource PointConverter}}"

, readonly Point ContextMenu. :

<ContextMenu x:Name="_menu" local:TrackBehavior.TrackOpenLocation="True">
    <MenuItem Command="..." CommandParameter="{Binding Path=(local:TrackBehavior.OpenLocation), ElementName=_menu}"/>
</ContextMenu>

TrackOpenLocation ContextMenu (OpenLocation) , ContextMenu. MenuItem OpenLocation, , ContextMenu.

+5

, ( Josh Smith ):

public static class TrackBehavior
{
 public static readonly DependencyProperty TrackOpenLocationProperty = DependencyProperty.RegisterAttached("TrackOpenLocation", typeof(bool), typeof(TrackBehavior), new UIPropertyMetadata(false, OnTrackOpenLocationChanged));

 public static bool GetTrackOpenLocation(ContextMenu item)
 {
  return (bool)item.GetValue(TrackOpenLocationProperty);
 }

 public static void SetTrackOpenLocation(ContextMenu item, bool value)
 {
  item.SetValue(TrackOpenLocationProperty, value);
 }

 public static readonly DependencyProperty OpenLocationProperty = DependencyProperty.RegisterAttached("OpenLocation", typeof(Point), typeof(TrackBehavior), new UIPropertyMetadata(new Point()));

 public static Point GetOpenLocation(ContextMenu item)
 {
  return (Point)item.GetValue(OpenLocationProperty);
 }

 public static void SetOpenLocation(ContextMenu item, Point value)
 {
  item.SetValue(OpenLocationProperty, value);
 }

 static void OnTrackOpenLocationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
 {
  var menu = dependencyObject as ContextMenu;
  if (menu == null)
  {
   return;
  }

  if (!(e.NewValue is bool))
  {
   return;
  }

  if ((bool)e.NewValue)
  {
   menu.Opened += menu_Opened;

  }
  else
  {
   menu.Opened -= menu_Opened;
  }
 }

 static void menu_Opened(object sender, RoutedEventArgs e)
 {
  if (!ReferenceEquals(sender, e.OriginalSource))
  {
   return;
  }

  var menu = e.OriginalSource as ContextMenu;
  if (menu != null)
  {
   SetOpenLocation(menu, Mouse.GetPosition(menu.PlacementTarget));
  }
 }
}

Xaml, :

<ContextMenu x:Name="menu" Common:TrackBehavior.TrackOpenLocation="True">
 <MenuItem Command="{Binding SomeCommand}" CommandParameter="{Binding Path=(Common:TrackBehavior.OpenLocation), ElementName=menu}" Header="Menu Text"/>
</ContextMenu>

:

NameScope.SetNameScope(menu, NameScope.GetNameScope(this));

, CommandParameter ElementName=menu.

+4

In addition to Kent's answer, think of a “standard way.” FE when the ListBox has ContextMenu, you do not need a menu position because the selected item is set before the menu appears. So, if your control has something that will be "selected" by right-clicking ...

+1
source

All Articles