2011-09-12 13 views
16

Desidero riutilizzare i miei UserControls in altri UserControls come pagina o finestra come DataTemplates, in questo esempio all'interno di un ListBox. Tutto è MVVM.UserControl come DataTemplate all'interno di ListBox

Ho un controllo utente denominato "CardControl" per visualizzare un oggetto semplice "Scheda". La carta ha due proprietà, "ID" e "CardImage". I controlli DataContext sono impostati tramite XAML. Se apro questo UserControl in VS o Blend, mi mostra la dummy Card che ho definito nel corrispondente ViewModel.

Ora ho un altro UserControl chiamato "CardSetControl", che dovrebbe visualizzare una raccolta di schede. Quindi ViewModel ha una proprietà di tipo ObservableCollection <Card> chiamata "Carte".

Ecco il codice:

<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}"> 
    <ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel> 

     <!-- WORKING, but not what i want --> 
     <TextBlock Text="{Binding ID}" /> // would display ID of Card 
     <Image Source="{Binding Image}" /> // would display Image of Card 

     <!-- NOT WORKING, but this is how i want it to work --> 
     <UserControls:CardControl DataContext="{Binding "Current listbox item as DataContext of CardControl???"}" /> 

     </StackPanel> 
    </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Dopo aver letto tonnellate di articoli su MVVM e DataContext/Binding non ho ancora farlo funzionare. In che modo tutta questa cosa gerarchica USerControls/DataContexts ha fatto il modo migliore e pulito?

risposta

13

Per il controllo ListBox un ListBoxItem inferito viene creata per ciascun elemento sorgente articoli. L'articolo è impostato come DataContext e il tuo ItemTemplate è impostato come modello. Dal momento che DataContext eredita, non è necessario impostarlo esplicitamente perché è già l'istanza di Card nel DataTemplate.

Per questo caso, non è necessario impostare la CC sul CardControl perché è impostato per voi.

<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}"> 
    <ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel> 

     <!-- WORKING, but not what i want --> 
     <TextBlock Text="{Binding ID}" /> // would display ID of Card 
     <Image Source="{Binding Image}" /> // would display Image of Card 

     <!-- NOT WORKING, but this is how i want it to work --> 
     <UserControls:CardControl /> 

     </StackPanel> 
    </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Dovrebbe funzionare per voi.

14

Nel tuo esempio, il DataContext dello UserControl sarebbe la scheda attualmente selezionata. Sfocia nel UserControl e i suoi controlli secondari come qualsiasi altro UIElement ricevono il controllo principale da parte di DataContext.

Ciò funziona:

<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}"> 
    <ListBox.ItemTemplate> 
    <DataTemplate> 
     <UserControls:CardControl /> 
    </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Dove CardControl è:

<UserControl x:Class="MySolution.CardControl" 
      OtherProperties="Not shown to keep this example small"> 
     <StackPanel> 
     <TextBlock Text="{Binding ID}" /> 
     <Image Source="{Binding Image}" /> 
     </StackPanel> 
</UserControl> 
+0

Will, le mie scuse ho praticamente dato la stessa risposta esatta come te.Dovrei aggiornare la pagina prima di rispondere la prossima volta;) –

+0

In questo modo un modello (Card) viene passato come DataContext al controllo utente. Cosa succede se mi piacerebbe che quel controllo utente utilizzasse il suo modello di visualizzazione? Come devo passare questo modello ricevuto a un modello di vista e associare il modello di vista alla vista del controllo? –

+0

@OndrejJanacek: UserControls non deve essere progettato per avere i propri modelli di visualizzazione. Dovrebbero avere proprietà pubbliche associabili sulla loro superficie che gli utenti si legheranno ai propri modelli di vista. Questa risposta è più adatta all'OP che alle migliori pratiche:/ – Will

1

Grazie per le vostre risposte, ma ho scoperto che il mio problema era un altro che avevo menzionato. Se lo fai come hai descritto, posso vedere i miei UserControls (CardControl) usati come modello per gli oggetti ListBox e l'ID e l'immagine viene visualizzata correttamente.

Inoltre, mi sono sempre chiesto perché sia ​​possibile visualizzare ID e Immagine mentre non riesco a collegarmi ad altre proprietà che ho definito nel ViewModel.

Oggi ho trovato un articolo interessante sulla gerarchia di DataContext. Ci si dice che DataContext all'interno di un ListBox NON sia lo stesso DataContext della pagina in cui è presente il ListBox. Non l'ho visto prima quindi ho pensato di dover impostare il DataContext in qualche modo come ho accennato nel domanda. Ora posso legare a tutte le proprietà.

Ecco l'articolo: http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/

Problemi correlati