RelativeSource legatura di una ToolTip o ContextMenu
-
01-10-2019 - |
Domanda
Che cosa sto facendo male qui:?
<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 è in ambito di DataContext della finestra.
Help me pls.
Soluzione
Questo è difficile perché descrizione comandi non è parte del VisualTree. Qui si vede una soluzione di fresco per lo stesso problema con contextmenus. Allo stesso modo si può andare per la descrizione comandi.
Aggiorna
Purtroppo il collegamento è andato e non ho trovato più l'articolo citato.
Per quanto mi ricordo, il blog di riferimento ha mostrato come si legano a un DataContext di un altro VisualTree, che è spesso necessay quando vincolante da una descrizione comandi, un ContextMenu o di un'altra.
Un bel modo per fare questo, è quello di fornire l'istanza desiderata (ad esempio ViewModel) all'interno del Tag-proprietà del 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 ho provato e il suo tempo ho fatto l'ultima volta. Si prega di fare un commento, se non funziona per voi.
UPDATE 2
Mentre il link originale che questa risposta è stato tradotto è andato, mi ha colpito archive.org e trovato la voce blog originale . Eccolo, pari pari dal blog:
Perché un ContextMenu in WPF non esiste all'interno della struttura visiva di la tua pagina / finestra / controllo di per sé, l'associazione di dati può essere un po 'difficile. Ho cercato di alta e bassa in tutto il web per questo, e il più risposta comune sembra essere “just do it nel codice dietro”. SBAGLIATO! io non è venuto per il meraviglioso mondo di XAML di essere tornare a fare le cose nel codice dietro.
Ecco il mio esempio per che vi permetterà di legarsi a una stringa che esiste come una proprietà della 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 contiene un riferimento a la finestra padre. ContextMenu è in grado di accedere a questo attraverso di essa della struttura PlacementTarget. È quindi possibile passare questo contesto verso il basso attraverso voci di menu.
Lo ammetto questa non è la soluzione più elegante del mondo. Tuttavia, batte roba impostazione nel codice dietro. Se qualcuno ha un ancora migliore modo per fare questo mi piacerebbe sentire.
Altri suggerimenti
Per di seguito:
PlacementTarget è il controllo che possiede il ContextMenu (es: DataGrid). Non c'è bisogno di una proprietà "tag".
IsEnabled si lega al valore "myProperty" del DataGrid.
Ho provato questo e funziona. Stava avendo problema simile con il legame.
<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"
>
A causa ContextMenu
non è nella struttura visiva, vincolante non funzionerà.
una soluzione semplice utilizza pattern Proxy, è possibile creare una classe wrapper che eredita da DependencyObject
e ha un DependencyProperty
che manterrà un DataContext
del vostro Window
, allora si può avere una risorsa della delega in XAML e, infine, si legano vostro comando MenuItem
al tuo comando desiderato tramite l'oggetto proxy.
Esempio Proxy:
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>
Che cosa sta succedendo?
Proprietà Data
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 riutilizzare in più viste e progetti.
Credo che dovrebbe essere fatto in questo modo:
{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"