2009-06-17 9 views
5

興味深い問題は、私は私のコントロール、InsertRowCmdに行を挿入するためのコマンドを起動したい... WPFのコマンドには、コンテキストメニュー項目からコマンドを発射に関連

をのContextMenuの原点を通ります。このコマンドは、行を挿入する場所を知る必要があります。

私はMouse.GetPosition()を使用することができましたが、それは現在マウスの位置を取得します。これはメニュー項目の上になります。私は代わりにコンテキストメニューの起源を取得したい。

コンテキストメニューの原点をパラメータとしてコマンドに渡す方法についての提案はありますか?

サンプルコード:

- 使用クリックハンドラを代わりに私は、コードの原点を見つけることができるように、次のように

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

私の現在の考え方

です。問題は、有効化/無効化を処理する必要があることです。

- イベントをクリックしてコンテキストメニューの原点を保存します。この保存された情報をコマンドに渡します。コマンドが実行される前にクリックイベントが発生することを確認しました。

アイデア?

EDIT:

私は私のViewModelクラスに取り扱うジョシュ・スミスのCommandSinkBindingルートへのコマンドを使用しています。したがって、コマンドの実行を処理するコードはビューについて何も知らない。

答えて

5

TranslatePointを使用すると、ContextMenuの左上(0、0)を含むグリッドの座標に変換する必要があります。あなたはContextMenuCommandParameterを結合することによってそれを行うと、コンバータを使用することができます。

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

別のアプローチは、ContextMenuが開かれるたびに自動的にタイプPointの添付読み取り専用プロパティを更新取り付けた行動だろう。

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

のでTrackOpenLocation添付プロパティがContextMenuに取り付け、ContextMenuが開かれるたびに二添付プロパティ(OpenLocation)の更新作業を行います。使用方法は、次のようになります。その後MenuItemOpenLocationにバインドして、ContextMenuが最後に開かれた場所を取得できます。

+0

"ConverterParameter"ではなく、最初に "CommandParameter"を意味すると思いますか? –

+0

あなたは添付の行動の考え方について詳しく説明しますか? –

+0

はい、ありがとう - 固定され、精巧さ。 –

1

ケントの答えに加えて、「標準的な方法」について考える。 F.e. ListBoxにContextMenuがある場合、メニューがポップアップする前に選択された項目が設定されているため、メニューの位置は必要ありません。コントロールが右クリックで「選択」されたものを持っていればケントの答えに続き

+0

Hmmm ...これにはいくつかの可能性があります。 –

+0

私は両方のあなたの提案を使用して終了しました。クリックが子コントロールにない場合があります。そのため、添付のビヘイビアを使用してポイントトランスレーションに関するKentの提案が必要です。アイテムが選択されたら、そのアイテムを代わりに使用しました。ありがとう! –

4

は、私は彼の添付プロパティの提案を使用し、(ジョシュ・スミスのexample for attached behaviorsを使用して)これで終わった:

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で使用するために、あなただけの必要があります。

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

詐欺に:しかし、私も追加する必要が

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

私のビューの構造体でなければ、CommandParameterのバインドはElementName=menuを検索できませんでした。

+0

私は名前のスコープと同じ問題があったと思います。投稿に感謝します。 –

+1

NameScopeハックの必要性を排除する別の解決方法は、RelativeSourceバインディングを使用することです:CommandParameter = "{Binding Path =(Common:TrackBehavior.OpenLocation)、RelativeSource = {RelativeSource AncestorType = ContextMenu}}"。これは私のためにうまくいった。 –

関連する問題