2017-01-02 38 views
1

MenuItemのコマンドパラメータを親Grid DataContextにバインドするにはどうすればよいですか?MenuItemから親DataGridへのCommandParameterのバインド

私はContextMenuを持つDataGridを持っており、メニュー項目をViewModelコマンドにバインドしますが、コマンドパラメータは常にnullです。

DataGridにTagパラメータを使用してDataContextにアクセスし、目的のコマンドを使用しますが、すべての行のバインディングデータを取得してコマンドパラメータとして使用することができます。

私はすでに多くの答えを見てきましたが、動作する人がいないため、ViewModel内のコマンドパラメータが呼び出され、コマンドパラメータは常にnullです。

C#

public class People 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class PeopleWindowViewModel 
{ 
    public List<People> Peoples { get; set; } 

    public PeopleWindowViewModel() 
    { 
     // populate Peoples list... 
    } 

    public ICommand RemoveCommand 
    { 
     get 
     { 
      return RelayCommand.Create((m) => 
      { 
       // m always null 
      }); 
     } 
    } 
} 

public class PeoplePage : Page 
{ 
    public PeoplePage() 
    { 
     InitializeComponent(); 

     DataContext = new PeopleWindowViewModel(); 
    } 
} 

XAML:

<DataGrid 
     Margin="0 8 0 8" 
     d:DataContext="{d:DesignInstance local:People}" 
     IsReadOnly="True" 
     ItemsSource="{Binding Peoples}" 
     Tag="{Binding DataContext, 
         RelativeSource={RelativeSource AncestorType={x:Type Page}}}"> 
    <DataGrid.Columns> 
     <DataGridTextColumn 
      Binding="{Binding Id}" 
      Header="Id" /> 
     <DataGridTextColumn 
      Binding="{Binding Name}" 
      Header="Name" /> 
    </DataGrid.Columns> 

    <DataGrid.ContextMenu> 
     <ContextMenu 
      Tag="{Binding Path=PlacementTarget.Tag, 
           RelativeSource={RelativeSource Self}}"> 
     <MenuItem 
      Command="{Binding PlacementTarget.Tag.RemoveCommand, 
             RelativeSource={RelativeSource Mode=FindAncestor, 
                    AncestorType=ContextMenu}}" 
      CommandParameter="{Binding Path=Id, 
               RelativeSource={RelativeSource Mode=FindAncestor, 
                       AncestorType=DataGrid}}" 
      Header="Remover" /> 
     </ContextMenu> 
    </DataGrid.ContextMenu> 
    </DataGrid> 
</Page> 
+0

ちょうど1つの質問ですので、私はあなたを助けることができます:コンテキストメニューはDataGrid行のコンテキストにする必要があります。 –

+0

@RodrigoVedovatoはい! – Trxplz0

答えて

2

私は解決策を見つけましたが、私はより良い1が存在しないかはわかりません。

<DataGrid ItemsSource="{Binding Peoples}"> 
    <DataGrid.Resources> 
     <ContextMenu x:Key="ctx_menu"> 
      <ContextMenu.Resources> 
       <Style TargetType="{x:Type MenuItem}"> 
        <Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" /> 
       </Style> 
      </ContextMenu.Resources> 
      <MenuItem Command="{Binding DataContext.RemoveCommand}" 
         CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" 
         Header="Remove" /> 
     </ContextMenu> 
    </DataGrid.Resources> 

    <DataGrid.ItemContainerStyle> 
     <Style TargetType="{x:Type DataGridRow}"> 
      <Setter Property="ContextMenu" Value="{StaticResource ctx_menu}" /> 
     </Style> 
    </DataGrid.ItemContainerStyle> 

</DataGrid> 

編集:とにかく、あなたはこのようにそれを行うことができますこれは、あなたは全体の人々はCommandParameterとしてオブジェクトを提供します。あなただけのIdをしたい場合は、単ににCommandParameterを変更します。

CommandParameter="{Binding PlacementTarget.DataContext.Id, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" 
+0

ありがとうございます。あなたのソリューションは魅力的に機能します。 私は何か別の方法があるかどうかを見るために、それを数時間無回答にします。 – Trxplz0

+0

よろしくお願いします! =) –

+0

"ContextMenu"を使ってこれをとして保持する方法はありますか? ContextMenuがDataGrid.ContextMenuでない場合、コマンドが呼び出されますが、UIライブラリが壊れます。 – Trxplz0

0

あなたはUI-LIBのためにあなたのDataGrid内のContextMenuを維持する必要がある場合は、あなたが知っている必要があり、あなたのケースでは、一般的に悪い習慣のthats。コンテキストメニューはコンテキストが必要な場所に移動する必要があります。これはあなたの行です。 しかし、とにかく、ある種の醜い「解決策」があります。ここにあるのは:

あなたのXamlでは、コマンドをバインドしてCommandParameterを無視します。あなたのICommandの方法では

<DataGrid ItemsSource="{Binding Peoples}"> 
    <DataGrid.ContextMenu> 
     <ContextMenu> 
      <MenuItem Command="{Binding RemoveCommand}" 
         Header="Remove" /> 
     </ContextMenu> 
    </DataGrid.ContextMenu> 
</DataGrid> 

、あなたがこれを行う:

private void Remove(object obj) 
{ 
    obj = Mouse.DirectlyOver as FrameworkElement; 
    if (obj != null) 
     obj = ((FrameworkElement)obj).DataContext; 

    // obj should be one People here 
} 

これは、ほとんどのシナリオのために働く必要がありますが、実際には、一般的にはあなたがこのような何かを避けるようにしてください。

関連する問題