2013-03-22 12 views
9

Ich möchte ein Kontextmenü an eine Liste von Befehlen binden.ContextMenu in MVVM

<Grid.ContextMenu> 
    <ContextMenu ItemsSource="{Binding ItemContextCommands, Converter={StaticResource commandToStringConverter}}"> 
      <ContextMenu.ItemTemplate > 
        <DataTemplate DataType="MenuItem"> 
          <MenuItem Command="{Binding}"></MenuItem> 
         </DataTemplate> 
       </ContextMenu.ItemTemplate> 
     </ContextMenu> 
</Grid.ContextMenu> 

Die commandToStringConverter wandelt einfach eine Liste von Befehlen, um eine Liste von Strings, die ToString() auf jeden Befehl in der Liste aufrufen.

Wie kann ich erreichen, dass die Command in jedem MenuItem heißt?

+0

Sie * probabbly * denken sollte einen anderen noch Konverter über die Verwendung, die jeder einzelne {Binding} zum eigentlichen Befehlsaufruf umwandelt. – Tigran

+0

der Konverter gibt eine Liste von Func zurück? –

Antwort

16

Ich würde ein kleines "View-Modell" verwenden, um die Informationen für einen solchen Befehl zu halten.

class ContextAction : INotifyPropertyChanged 
{ 
    public string Name; 
    public ICommand Action; 
    public Brush Icon; 
} 

machen eine Sammlung im View-Modell, das die Kontext Aktionen wie

ObservableCollection<ContextAction> Actions {get;set;} 

und einfach binden diese Sammlung zu Ihren ContextMenu bekommen sollte.

Das ItemTemplate für die Kontextmenüelemente kann jetzt auf den Namen, den Befehl und alles, was Sie sonst noch benötigen, zugreifen. Es kann nützlich sein, das CommandParameter auch so zu ändern, dass es den Befehl mit dem Element actions owning aufruft, nicht mit der Aktion selbst.

+1

+1 Sie waren schneller :) – blindmeis

+0

Jeder hat eine Idee, wie man ein ContextMenu mit Separatoren und Untermenüs behandelt? Diese Lösung scheint nur für einen homogenen Satz von Objekten nützlich zu sein. –

+0

Submenüs sind genauso einfach. Sie geben dem ContextMenu nur einen ItemContainerStyle mit einem Setter für ItemsSource und binden an eine neue Eigenschaft des Typs ObservableCollection in einer ContextAction. Für Separatoren siehe [diese] (http://stackoverflow.com/questions/4823760/how-to-add-horizontal-separator-in-a-dynamically-created-contextmenu) Lösung. – dowhilefor

11

ich verwende etwas wie folgt aus:

public class ContextMenuVM 
{ 
    public string Displayname {get;set;} 
    public ICommand MyContextMenuCommand {get;set;} 
} 

in Ihrem contextmenu Datacontext:

public ObservableCollection<ContextMenuVM> MyCommandList {get;set;} 

in XAML

<ContextMenu ItemsSource="{Binding MyCommandList}"> 
     <ContextMenu.ItemTemplate > 
       <DataTemplate DataType="MenuItem"> 
         <MenuItem Header="{Binding Displayname}" Command="{Binding MyContextMenuCommand}"></MenuItem> 
        </DataTemplate> 
      </ContextMenu.ItemTemplate> 
    </ContextMenu> 

ihren schriftlichen ohne ide, vielleicht einige Syntaxfehler in dort

+3

Diese Lösung verfügt über ein geschachteltes Steuerelement für MenuItem –

2

Eine verbesserte XAML-Version @blindmils Lösung unter:

<ContextMenu ItemsSource="{Binding MyCommandList}"> 
    <ContextMenu.ItemContainerStyle> 
     <Style TargetType="MenuItem"> 
      <Setter Property="Header" Value="{Binding Displayname}" /> 
      <Setter Property="Command" Value="{Binding MyContextMenuCommand }" /> 
     </Style> 
    </ContextMenu.ItemContainerStyle> 
</ContextMenu>