2017-01-02 6 views
1

Wie kann ich einen Befehlsparameter von MenuItem an übergeordneten Grid DataContext binden?CommandParameter von MenuItem an übergeordnetes DataGrid binden

Ich habe ein DataGrid mit ContextMenu, das die Menüelemente an ViewModel-Befehle bindet, aber der Befehlsparameter ist immer null.

Ich verwende Tag-Parameter in DataGrid, um Zugriff auf DataContext zu erhalten und den gewünschten Befehl zu verwenden, könnte aber herausfinden, dass die Bindungsdaten aus jeder Zeile als Befehlsparameter verwendet werden.

Ich hatte bereits viele Antworten hier untersucht, konnte aber niemanden finden, der funktioniert, der Befehlsparameter im ViewModel wird aufgerufen und der Befehlsparameter ist immer 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

Nur eine Frage, damit ich Ihnen helfen kann: Sie müssen das Kontextmenü kontextuell für die DataGrid-Zeile, richtig? –

+0

@RodrigoVedovato ja !!! – Trxplz0

Antwort

2

ich eine Lösung gefunden, aber ich bin nicht sicher, ob es nicht besser ist. Wie auch immer, man kann es wie folgt tun:

<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> 

Edit: das gibt Ihnen das ganze Volk als Command Objekt. Wenn Sie nur die Id wollen, sondern nur die Commandparameter ändern:

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

Vielen Dank, Ihre Lösung funktioniert wie ein Zauber. Ich werde es für ein paar Stunden unbeantwortet lassen, nur um zu sehen, ob jemand einen anderen Weg hat, es zu tun. – Trxplz0

+0

Gern geschehen! =) –

+0

Gibt es eine Möglichkeit, das "ContextMenu" als zu verwenden? Auf diese Weise werden die Befehle aufgerufen, aber meine UI-Bibliothek bricht, wenn das ContextMenu kein DataGrid.ContextMenu ist. – Trxplz0

0

Wenn Sie das ContextMenu in Ihrem Datagrid für den UI-LIB zu halten haben, müssen Sie wissen, das ist im Allgemeinen schlechte Praxis in Ihrem Fall. Das Kontextmenü sollte dorthin führen, wo Sie den Kontext von ... benötigen und das sind Ihre Zeilen. Aber irgendwie gibt es eine Art hässliche "Lösungen". Hier ist eine:

In Ihrem Xaml nur den Befehl binden und das CommandParameter ignorieren.

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

In Ihrer ICommand Methode, Sie dies tun:

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

    // obj should be one People here 
} 

Dies ist für die meisten Szenarien funktionieren soll, aber wirklich, versuchen im Allgemeinen Sie so etwas wie dies zu vermeiden.

Verwandte Themen