2013-02-22 22 views
20

Ho qualche problema nel capire come impostare il DataContext corretto su un ContextMenu.WPF ContextMenu woes: Come imposto il DataContext del ContextMenu?

Ho una collezione di modelli di visualizzazione che sono la fonte di uno ItemsControl. Ogni modello di vista ha una collezione di elementi che sono anche la fonte di un altro ItemsControl. Ogni elemento è utilizzato per disegnare un'immagine che ha un ContextMenu. Lo MenuItems in quello ContextMenu deve eseguire il binding a un comando sul modello di visualizzazione, ma lo PlacementTarget di ContextMenu punta al singolo elemento.

mio Xaml sembra qualcosa di simile:

<ItemsControl ItemsSource="{Binding Markers"}> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <ItemsControl ItemsSource="{Binding Items}"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <Image> 
          <Image.ContextMenu> 
           <ContextMenu> 
            <MenuItem Header="Edit" Command="{Binding EditCommand}" /> 
           </ContextMenu> 
          </Image.ContextMenu> 
         </Image> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Come posso impostare la DataContext del ContextMenu al corrispondente vista del modello padre del articolo?

risposta

35

ContextMenu si trova all'esterno dell'albero visivo. Di seguito è riportato il codice XAML che dovrebbe ottenere il DataContext:

<ItemsControl ItemsSource="{Binding Markers}" Tag="{Binding ElementName=outerControl, Path=DataContext}"> 
    ... 
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"> 
     <MenuItem Header="Edit" 
       Command="{Binding EditCommand}" /> 
    </ContextMenu> 
    ... 
</ItemsControl> 

Questo post spiega come funziona.

+1

Il problema di questo è che non voglio legare a ciò che il PlacementTarget è. Voglio collegarmi al DataContext del controllo esterno. –

+0

Sei sicuro di non avere lo stesso DataContext (cioè outerControl e inner itemsControl)? – kevindaub

+0

Sì, il DataContext che ottengo utilizzando PlacementTarget è un livello troppo profondo. Torno a un elemento, ma quello di cui ho bisogno è il modello di vista che ha la collezione che contiene quell'oggetto. Se potessi legarmi al DataContext del controllo esterno, sarebbe perfetto. –

8

È possibile utilizzare un MarkupExtension:

using System; 
using System.Windows.Controls; 
using System.Windows.Markup; 
using System.Xaml; 

[MarkupExtensionReturnType(typeof(ContentControl))] 
public class RootObject : MarkupExtension 
{ 
    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider)); 
     return rootObjectProvider?.RootObject; 
    } 
} 

Ti permette di fare:

<ItemsControl ItemsSource="{Binding Markers}"> 
    ... 
    <ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}"> 
     <MenuItem Header="Edit" 
       Command="{Binding EditCommand}" /> 
    </ContextMenu> 
    ... 
</ItemsControl> 
+1

Ah Sì, venerdì 4 ore e questo funziona! – grunge

2

Non mi piace l'uso di tag. Preferisco la proprietà attaccata.

dovete aggiungere proprietà associata:

public static readonly DependencyProperty DataContextExProperty = DependencyProperty.RegisterAttached("DataContextEx", typeof(Object), typeof(DependencyObjectAttached)); 

    public static Object GetDataContextEx(DependencyObject element) 
    { 
     return element.GetValue(DataContextExProperty); 
    } 

    public static void SetDataContextEx(DependencyObject element, Object value) 
    { 
     element.SetValue(DataContextExProperty, value); 
    } 

In XAML:

<Button attached:DependencyObjectAttached.DataContextEx="{Binding ElementName=MyDataContextElement, Path=DataContext}"> 
     <Button.ContextMenu> 
      <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.(attached:DependencyObjectAttached.DataContextEx)}"> 

      </ContextMenu> 
     </Button.ContextMenu> 
    </Button>