문제

상황에 맞는 메뉴 항목에서 명령을 실행하는 것과 관련된 흥미로운 문제입니다...

내 컨트롤에 행을 삽입하는 명령인 InsertRowCmd를 실행하고 싶습니다.이 명령은 행을 삽입할 위치를 알아야 합니다.

Mouse.GetPosition()을 사용할 수 있지만 이렇게 하면 현재 메뉴 항목 위에 있는 마우스의 위치를 ​​알 수 있습니다.대신 컨텍스트 메뉴의 원점을 얻고 싶습니다.

상황에 맞는 메뉴의 원본을 명령에 대한 매개 변수로 전달하는 방법에 대한 제안 사항이 있는 사람이 있습니까?

샘플 코드:

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

나의 현재 아이디어는 다음과 같습니다.

- 코드에서 원점을 찾을 수 있도록 대신 클릭 핸들러를 사용하세요.문제는 활성화/비활성화를 처리해야 한다는 것입니다.

-클릭 이벤트를 처리하고 컨텍스트 메뉴의 출처를 저장합니다.이 저장된 정보를 명령에 전달하십시오.명령이 실행되기 전에 클릭 이벤트가 실행되는 것을 확인했습니다.

어떤 아이디어가 있나요?

편집하다:

저는 Josh Smith의 제품을 사용하고 있습니다. 명령SinkBinding 명령 처리를 내 ViewModel 클래스로 라우팅합니다.따라서 명령 실행을 처리하는 코드는 뷰에 대해 아무것도 모릅니다.

도움이 되었습니까?

해결책

당신은 사용해야합니다 TranslatePoint 왼쪽 상단(0, 0)을 변환하려면 ContextMenu 포함하는 그리드의 좌표로.바인딩하면 그렇게 할 수 있습니다. CommandParameter ~로 ContextMenu 변환기를 사용하십시오.

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

또 다른 접근 방식은 연결된 읽기 전용 속성 유형을 자동으로 업데이트하는 연결된 동작입니다. 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 마지막으로 열렸습니다.

다른 팁

Kent의 답변에 이어 나는 그가 첨부한 부동산 제안을 사용하여 다음과 같이 결론을 내렸습니다(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.

Kent의 답변 외에도 "표준 방식"을 생각해보십시오.F.e.ListBox에 ContextMenu가 있으면 메뉴 위치가 필요하지 않습니다. 선택한 항목은 메뉴가 나타나기 전에 설정되기 때문입니다.따라서 컨트롤에 마우스 오른쪽 버튼을 클릭하면 "선택"되는 항목이 있는 경우...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top