2012-04-03 32 views
17

私は、コマンドをWPFのメニューアイテムにバインドしようとしています。私は他のすべてのコマンドバインディングのために働いていたのと同じ方法を使用していますが、ここではうまくいかない理由がわかりません。コンテキストメニューへのMVVMバインディングコマンド

私は現在、このように私のコマンドを結合しています:

Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MyCommand}" 

それがうまくいかないところです(これはユーザーコントロールの内部にある)

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
         Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}"> 

    <Button.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="Remove" CommandParameter="{Binding Name}" 
             Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RemoveCommand}"/> 
     </ContextMenu> 
    </Button.ContextMenu> 
    ... 

それが必要のような最初のコマンドバインディングの作品は、 2人目は何もしません。 祖先のレベルを変更し、RelativeSourceの代わりにElementNameを使用してアクセスするようにコントロールを命名しようとしましたが、変更はありません。それは "参照とのバインディングのソースを見つけることができません..."と続きます

私は何が欠けていますか?あなたはこれを言及しているので

+1

私がチェックする必要があると思いますが、技術的にそれはだから、それがユーザーコントロールを見つけることができませんので、MenuItemには、別の木であってもよく、祖先ではない(スヌープは私がこの権利を覚えているかどうかを確認することができた)。他のコマンドバインディング(Buttonコントロールのコマンドなど)では、なぜCommand = "{Binding Path = ConnectCommand}"を実行できませんか? ButtonはUserControlからDataContextを継承する必要があるため、RelativeSource/FindAncestorの構文全体を必要としません。 – MetalMikester

答えて

25

(編集)のItemsControlのテンプレートである、物事は異なっている:

1)このブログ(これは興味深い情報であるとして、ブログを読んで)からBindingProxyクラスを取得します:How to bind to data when the DataContext is not inherited

基本的に、ItemsControl(またはContextMenu)の要素は、ビジュアルツリーまたは論理ツリーの一部ではないため、UserControlのDataContextを見つけることができません。私はここにこれ以上書いていないことに謝罪しますが、作者はそれを一歩一歩説明してくれているので、ほんの数行で完全な説明をすることはできません。 (あなたはそれがあなたのコントロールで動作させるために、それを少し適応する必要がある場合があります):

2)は、このような何かを行います。これにより、StaticResourceを使用してUserControl DataContextにアクセスできます。

<UserControl.Resources> 
<BindingProxy 
    x:Key="DataContextProxy" 
    Data="{Binding}" /> 
</UserControl.Resources> 

b。これは、木やデータグリッドのようなもので、私たちのために働いている

<Button.ContextMenu> 
<ContextMenu> 
    <MenuItem Header="Remove" CommandParameter="{Binding Name}" 
     Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/> 
</ContextMenu> 

:これは、(A)で定義されてDataContextProxyを使用しています。

+0

このボタンはItemsControl ItemTemplateの一部です。私はItemsControlのためのバインディングとして使用されるモデルのコレクションを持っています。これは、それらのモデルにないためにコマンドをバインドする単純な方法が機能しなかった理由です私はまだそれはほとんど魔法です) – Valyrion

+1

ああ、それは違うが、XamDataTree(Infragisticsツリーコントロール)で同じことをやらなければならなかった。私があなたのために情報を見つけさせてください(私がする前に誰も解決策を投稿していない場合):) – MetalMikester

+0

@Baboonは説明するように気をつけますか? – SZT

11

ContextMenuは異なる論理ツリーにあります。そのため、RelativeSourceは機能しません。しかし、コンテクストメニューは "コンテナ"からDataContextを継承します。この場合はButtonです。あなたのケースでは、ItemsControlアイテムとItemsControlの2つの "データコンテキスト"が必要です。 あなたはビューモデルを1つに統合し、ItemsControlアイテムデータコンテキストとして使用されるカスタムクラスを実装し、 "名前"と "削除コマンド"の両方を含むか、アイテムのビューモデルでRemoveCommand "proxy"その呼び出します親コマンドが内部

EDITは:私は少しヒヒのコードを変更し 、それはこのように動作する必要があります。必ずわずかにあなたがここに迅速な回避策を見つけるだろうが、

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
    Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" 
    Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}"> 
      <Button.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Remove" 
        CommandParameter="{Binding Name}" 
        Command="{Binding Path=PlacementTarget.Tag.DataContext.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/> 
       </ContextMenu> 
      </Button.ContextMenu> 
+0

それは動作します。私は元のコードを試みたときに "DataContext"の代わりに "Data"を使用していました。私はBindingProxyのアプローチに固執します - 構文は少し重いですが、とりわけ、いくつかのオブジェクトにTagを使用していくつかの追加情報を渡すことがあり、私たちが使用しているポイントこのアプローチは、タグが2つの異なる目的のために必要とされるシナリオに入る。しかし、オプションがあるニース! – MetalMikester

3

難しい問題だですノーマジックソリューション:

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
     Tag={Binding} 
     Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">  
    <Button.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="Remove" 
         CommandParameter="{Binding Path=PlacementTarget.Tag.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" 
         Command="{Binding Path=PlacementTarget.Tag.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/> 
     </ContextMenu> 
    </Button.ContextMenu> 
... 

PlacementTargetTag(ここではButton)を使用しています。

+0

興味深い。 BindingProxyのアプローチを置き換えることができるかどうかを調べるには、私自身のことでそれを試さなければならないでしょう。 – MetalMikester

+0

実際には、私は元々、どこかのMSDNの例からそのことを推測しました。 –

+0

私はこれをXamDataTree ItemTemplateで簡単に試してみましたが、何もしません。コマンドを見つけることができません。 Slyderのケースではうまくいくでしょう - 周囲のコードなしでは言い難いです。 – MetalMikester

4

koshdimがスポット上にあり、魅力的に機能します!おかげKoshdim

私は私のコンテキストメニューに合わせて自分のコードを変更し

<DataGrid 
     AutoGenerateColumns="False" 
     HeadersVisibility="Column" 
     Name="dgLosses" 
     SelectedItem="{Binding SelectedItem, Mode= TwoWay}" 
     AllowDrop="True" 
     ItemsSource="{Binding Losses}" 
     Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"> 


     <DataGrid.ContextMenu > 
      <ContextMenu > 
       <MenuItem Header="Move to Top  " Command="{Binding PlacementTarget.Tag.MoveToTopCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem> 
       <MenuItem Header="Move to Period 1" Command="{Binding PlacementTarget.Tag.MoveToPeriod1Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem> 
       <MenuItem Header="Move to Period 2" Command="{Binding PlacementTarget.Tag.MoveToPeriod2Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem> 
       <MenuItem Header="Move to Period 3" Command="{Binding PlacementTarget.Tag.MoveToPeriod3Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>      
      </ContextMenu> 
     </DataGrid.ContextMenu> 
関連する問題