2013-03-19 32 views
6

io non sono sicuro se il mio colpo di testa parola rappresentano esattamente il mio problema, io farà il meglio per spiegare:DataContext multiple per un controllo - MVVM

Ho un DataTemplate cella della griglia: (la griglia appartengono a società di terze parti ma non `s importante per la mia domanda)

<DataTemplate> 
    <TextBlock> 
     <Hyperlink Command="{Binding OpenLinkCommand}"> 
      <Hyperlink.ToolTip> 
       <TextBlock Text="{Binding Data.MapLink}"/> 
      </Hyperlink.ToolTip> 
      <TextBlock Text="{Binding Data.MapLink}" TextDecorations="underline"> 
     </Hyperlink> 
    </TextBlock> 
</DataTemplate> 

voglio fare questa DataTemplate a mostrare qualche collegamento ipertestuale ("Data.MapLink" è l'oggetto che contengono il valore di collegamento) e ogni clic su questo link scatterà la comando "OpenLinkCommand".

Il problema è che "Data.MapLink" e "OpenLinkCommand" si trovano in diverse DataContext e poi devo scegliere una delle scelte seguenti:

  1. congedo collegamento ipertestuale DataContext in quanto - il comando won `funziona e il collegamento ipertestuale otterrà il valore Data.MapLink.

  2. cambiamento collegamento ipertestuale DataContext al comando DataContext - Il comando funzionerà, ma il nome di collegamento ipertestuale sarà vuoto.

Purtroppo ho indossare il `t put option tali elementi nella stessa DataContext quindi devo trovare un modo per dire al comando che si DataContext è "X" e dire il collegamento ipertestuale che DataContext è "Y".

Spero che la mia domanda è chiara Come posso risolvere questo problema?

+1

Da dove proviene il secondo datacontext? è legato a un elemento perché è possibile associare un dato datacontext a un altro e basta impostare la relativa sorgente. Se si ha accesso a entrambi i datacontext nel proprio modello di vista (supponendo che si stia utilizzando un viewmodel), è possibile inserire l'altro comando. – TYY

+0

utilizza RelativeSource nel tuo binding per trovare il datacontext corretto – blindmeis

+0

Ho appena segnalato il bug (un'altra volta?) A Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/1398835/binding-of-readonly-dependencyproperty –

risposta

15

Ci sono alcune proprietà di legame che è possibile utilizzare per specificare un diverso Source per la vostra associazione da quello predefinito DataContext

Il la maggior parte dei più comuni sono ElementName o RelativeSource, che sarà trovare un altro elemento dell'interfaccia utente nel VisualTree modo è possibile associare alla sua proprietà.

Ad esempio, il seguente utilizza ElementName a dire il legame che dovrebbe usare MyGridView come fonte di legame e di legarsi a MyGridView.DataContext.OpenLinkCommand

<Hyperlink Command="{Binding ElementName=MyGridView, 
          Path=DataContext.OpenLinkCommand}"> 

È inoltre possibile utilizzare RelativeSource in un legame di trovare ulteriormente un oggetto il VisualTree del tipo di oggetto specificato e utilizzarlo come origine di associazione. Questo esempio fa la stessa cosa dell'esempio sopra, eccetto che usa RelativeSource invece di ElementName, quindi il tuo GridView non ha bisogno di avere un Name specificato.

<Hyperlink Command="{Binding 
       RelativeSource={RelativeSource AncestorType={x:Type GridView}}, 
       Path=DataContext.OpenLinkCommand}"> 

Una terza opzione è quella di impostare la Source proprietà di legame a un oggetto statico, come questo:

<Hyperlink Command="{Binding 
       Source={x:Static local:MyStaticClass.OpenLinkCommand}}"> 

Sulla base your comment here sull'associazione ad un Singleton, questo sarebbe probabilmente l'opzione migliore per voi .

+0

Ciao, La tua soluzione sembra essere quella che sto cercando. Lo proverò oggi e riferirò se ha risolto il mio problema. – Ofir

+0

La soluzione sta funzionando eccellente !!! Thank youy – Ofir

+0

@Ofir Contento che ha funzionato per voi :) – Rachel

0

Si dovrà avere un'istanza del contesto dati desiderato (di solito nelle risorse di un controllo o una finestra). Una volta ottenuto ciò, dovresti essere in grado di impostare esplicitamente il contesto di dati del blocco di testo anziché ereditare automaticamente il contesto di dati padre.

Ad esempio:

<TextBlock DataContext="{StaticResource MyDataMapLinkDataContext}" Text="{Binding Data.MapLink}" TextDecorations="underline"/> 
+1

Sì, ho pensato a questo modo, ma non posso creare un'altra instace datacontext (il mio datacontext deve essere singleTon). Qualche altro suggerimento? – Ofir

+0

È possibile associare il collegamento ipertestuale al contesto dei dati padre utilizzando la risorsa relativesource FindAncestor. Il codice di binding esatto dipende da come hai strutturato il tuo xaml. Magari postare il tuo xaml se hai bisogno di aiuto con questo. – failedprogramming

+0

Inoltre, hai detto che non puoi mettere entrambi i comandi nello stesso datacontext, se stai usando mvvm, puoi racchiudere entrambi i modelli di vista in un terzo ed esporre entrambi i comandi. – failedprogramming

0

Se si ha realmente bisogno di utilizzare un'altra proprietà per un contesto dati in più allora si può solo utilizzare una proprietà associata.

XAML

<Window.Resources> 
     <Style TargetType="Button"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="Button"> 
         <ContentPresenter Content="{Binding (local:ExtraDataContextProvider.ExtraDataContext), RelativeSource={RelativeSource TemplatedParent}}"/> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </Window.Resources> 

    <Grid> 
     <Button Margin="172,122,131,79" Foreground="Green" local:ExtraDataContextProvider.ExtraDataContext="A test"> 
      test 
     </Button> 
    </Grid> 
</Window> 

Codice

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace WpfApplication1 
{ 

    public class ExtraDataContextProvider : DependencyObject 
    { 
     public static object GetExtraDataContext(DependencyObject obj) 
     { 
      return (object)obj.GetValue(ExtraDataContextProperty); 
     } 

     public static void SetExtraDataContext(DependencyObject obj, object value) 
     { 
      obj.SetValue(ExtraDataContextProperty, value); 
     } 

     public static readonly DependencyProperty ExtraDataContextProperty = DependencyProperty.RegisterAttached("ExtraDataContext", typeof(object), typeof(ExtraDataContextProvider), new PropertyMetadata(null)); 
    } 

    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 
    } 
}