2010-09-08 13 views
25

Che cosa sto facendo di sbagliato qui ?:RelativeSource vincolante da una descrizione comandi o ContextMenu

<GridViewColumn> 
    <GridViewColumn.CellTemplate> 
     <DataTemplate> 
      <Button> 
      <Button.ToolTip> 
       <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" /> 

Questo è solo un esempio semplificato, che non funziona in ogni caso :) In realtà ho bisogno di ottenere un valore da un'altra proprietà che è nell'ambito di DataContext della finestra.

Aiutami a pls.

risposta

63

Ciò è difficile perché ToolTip non fa parte di VisualTree. Here si vede una soluzione interessante per lo stesso problema con ContextMenus. Allo stesso modo puoi andare per la descrizione.

UPDATE
Purtroppo il link è andato e non ho trovato più l'articolo citato.
Per quanto mi ricordo, il blog di riferimento ha mostrato come associare a un DataContext di un altro VisualTree, che è spesso necessario quando si esegue il binding da una descrizione comando, un ContextMenu o un Popup.

Un buon modo per eseguire questa operazione è fornire l'istanza desiderata (ad esempio ViewModel) all'interno della proprietà Tag di PlacementTarget. L'esempio seguente fa questo per l'accesso a un comando di istanza di un ViewModel:

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}"> 
    <Button.ContextMenu> 
    <ContextMenu> 
     <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../> 
    <ContextMenu> 
    </Button.ContextMenu> 
</Button> 

non l'ho provato e la sua molto tempo ho fatto l'ultima volta. Si prega di fare un commento se non funziona per voi.

UPDATE 2

Come il link originale che questa risposta è stato tradotto è andato, mi ha colpito archive.org e found the original blog entry. Eccolo, pari pari dal blog:

Perché un ContextMenu in WPF non esiste all'interno della struttura visiva della tua pagina/finestra/controllo di per sé, l'associazione di dati può essere un po 'difficile. Ho cercato in alto e in basso sul Web per questo, e la risposta più sembra essere "basta farlo nel codice dietro". SBAGLIATO! I non è entrato nel meraviglioso mondo di XAML per tornare a facendo cose nel codice.

Ecco il mio esempio che vi permetterà di associare a una stringa che esiste come una proprietà della vostra finestra.

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     MyString = "Here is my string"; 
    } 

    public string MyString 
    { 
     get; 
     set; 

    } 
} 


<Button Content="Test Button" 
    Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"> 
    <Button.ContextMenu> 
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
      RelativeSource={RelativeSource Self}}" > 
     <MenuItem Header="{Binding MyString}"/> 
    </ContextMenu> 
    </Button.ContextMenu> 
</Button> 

La parte importante è il tag sul pulsante (anche se si potrebbe altrettanto facilmente impostare il DataContext del pulsante). Questo memorizza un riferimento a la finestra genitore. ContextMenu è in grado di accedere a questo tramite la proprietà PlacementTarget. È quindi possibile passare questo contesto attraverso le voci del menu.

Ammetto che questa non è la soluzione più elegante del mondo. Tuttavia, batte le impostazioni nel codice dietro. Se qualcuno ha un modo migliore di fare questo, mi piacerebbe sentirlo anche con il .

+0

Questo è! Grazie! – Agzam

+0

Questo link è morto. Puoi inserire le informazioni mancanti? –

+1

@Bill Non ho più trovato il collegamento ma ho cercato di spiegare il modo in cui il problema può essere risolto. – HCL

-2

penso che dovrebbe essere fatto in questo modo:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 
+0

No ... non funziona. Ho già provato quello ... – Agzam

+0

Questo non funziona perché il VisualTree principale non è disponibile dal ToolTip. Vedi la mia risposta. – HCL

+0

yah, mi dispiace, non ho nemmeno notato che era all'interno di un suggerimento. – mdm20

0

Perché ContextMenu non è in albero visuale, vincolante non funzionerà. una soluzione semplice utilizza Proxy Pattern, è possibile creare una classe wrapper che eredita da DependencyObject e ha un DependencyProperty che manterrà uno DataContext del proprio Window, quindi è possibile avere una risorsa del proxy in XAML e infine associare il comando MenuItem a il tuo comando desiderato tramite l'oggetto proxy. Proxy
Esempio:

Public class ProxyClass : DependencyObject 
{ 
    Public object Data {get; set;} 
    public static readonly DependencyProperty DataProperty = DependencyProperty.Register("DataProperty", typeof(object), typeof(ProxyClass), new FrameworkPropertyMetadata(null)); 

} 

Come utilizzare in XAML:

<Window DataContext="{Binding MyViewModel}"> 
... 
<Window.Resources> 
    <ProxyClass Data={Binding} x:Key="BindingProxy"/> 

</Window.Resources> 
... 
<MenuItem Command="{Binding Source={StaticResource BindingProxy}, Path=Data.MyDesiredCommand"/> 
... 
</Window> 

Cosa sta succedendo?
Data proprietà di ProxyClass si legherà DataContext di Window, allora ha tutte le vostre comamnds e proprietà del ViewModel all'interno della risorsa ProxyClass.
un altro vantaggio di questo approccio è la portabilità e il riutilizzo in più viste e progetti.

2

Per quanto segue:
PlacementTarget è il controllo proprietario di ContextMenu (ad esempio: DataGrid). Non c'è bisogno di una proprietà "tag".

IsEnabled si collega al valore "myProperty" del DataGrid.

Ho provato questo e funziona. Stavo avendo un problema simile con il binding.

<ContextMenu 
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}" 
IsEnabled="{Binding myProperty}" 
> 
Problemi correlati