2012-03-20 12 views
10

Possiedo un controllo Usercontrol (TabUserControl) che contiene un controllo TabControl. Il Viewmodel di quel UserControl carica una collezione Observable di TabItems. Uno di questi articoli è un altro controllo utente. Quando carico il testo nel tabcontrol non c'è alcun problema, ma come posso caricare l'altro controllo utente nel tabitem di TabUserControl. Sto usando MVVM.Carica UserControl in TabItem

Ecco il mio codice:

public class TabItem 
{ 
    public string Header { get; set; } 
    public object Content { get; set; } // object to allow all sort of items?? 
} 

ViewModel del TabUserControl

public class TabViewModel 
{ 
    public ObservableCollection<TabItem> Tabs {get;set;} 

    public TabViewModel() 
    { 
     Tabs = new ObservableCollection<TabItem>(); 
     //Tabs.Add(new TabItem { Header = "Overview", Content = new OverviewViewModel() }); How to load a usercontrol here if it's in the ItemCollection? 
     Tabs.Add(new TabItem { Header = "Overview", Content = "Bla bla bla" }); 
     Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" }); 
    } 
} 

E poi il TabControl XAML:

<TabControl x:Name="_tabControl" 
      ItemsSource="{Binding Tabs}"> 
    <TabControl.ItemContainerStyle> 
    <Style TargetType="TabItem"> 
     <Setter Property="Header" 
       Value="{Binding Header}" /> 
     <Setter Property="Content" 
       Value="{Binding Content}" /> 
    </Style> 
    </TabControl.ItemContainerStyle> 
</TabControl> 

Funziona finché io non caricare il ViewModel dell'usercontrol nella collezione tabItems. Come posso caricare UserTabControl sul TabItem? L'intenzione è che ogni tabitem conterrà un usercontrol. Ogni usercontrol quindi fa la propria cosa.

Spero che qualcuno possa aiutarmi visto che sono un principiante del WPF. Thx!

risposta

27

Idealmente, il TabControl.ItemsSource deve essere impostato su una raccolta di ViewModels, e DataTemplates dovrebbe essere usato per dire al WPF per disegnare ogni ViewModel con una specifica UserControl.

Ciò mantiene tra la logica di business (ViewModels) completamente separato dal UI (Views)

Per esempio,

<TabControl x:Name="MyTabControl" 
      ItemsSource="{Binding TabViewModels}" 
      SelectedItem="{Binding SelectedTabViewModel}"> 

    <TabControl.Resources> 
     <DataTemplate DataType="{x:Type my:ViewModelA}"> 
      <my:ViewAUserControl /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type my:ViewModelB}"> 
      <my:ViewBUserControl /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type my:ViewModelC}"> 
      <my:ViewCUserControl /> 
     </DataTemplate> 
    </TabControl.Resources> 

    <TabControl.ItemContainerStyle> 
     <Style TargetType="TabItem"> 
      <Setter Property="Header" Value="{Binding Header}" /> 
     </Style> 
    </TabControl.ItemContainerStyle> 

</TabControl> 

ViewModel contenenti DataContext del TabControl:

TabViewModels = new ObservableCollection<ITabViewModel>(); 
TabViewModels.Add(new ViewModelA { Header = "Tab A" }); 
TabViewModels.Add(new ViewModelB { Header = "Tab B" }); 
TabViewModels.Add(new ViewModelC { Header = "Tab C" }); 

SelectedTabViewModel = TabViewModels[0]; 
+0

Ciao Rachel. Grazie per i tuoi commenti. Capisco la logica che stai dicendo, ma sono un po 'preoccupata per farlo funzionare. Soprattutto la parte di ITabViewModel, da dove la prendi? Un'altra parte della mia domanda è come posso fare questo se non so quante schede dovrebbero essere aggiunte? Sono sempre sicuro di almeno una scheda, ma altre schede dovrebbero essere aggiunte quando clicco su un pulsante. Thx per il tuo aiuto. – PitAttack76

+0

@ Stieven76 'ITabViewModel' è semplicemente un'interfaccia che definisce una proprietà' Header'. I ViewModels A, B e C erederebbero tutti da 'ITabViewModel', quindi condivideranno tutti la stessa classe base.Dato che stai usando MVVM, la proprietà 'Command' di Button dovrebbe puntare a un comando nel' ViewModel', che aggiungerebbe semplicemente un nuovo oggetto alla raccolta 'TabViewModels', e probabilmente lo imposterà come selezionato. – Rachel

+0

Thx Rachel. Ho funzionato nel modo che voglio. Grazie per l'aiuto! – PitAttack76

2

Grazie Rachel la tua risposta. Ma impone di dichiarare il DataContext durante la compilazione stessa. Come hai fatto tu, collegando ciascuna delle Views ai rispettivi ViewModels nel DataTemplate di TabControl. Possiamo raggiungere il collegamento dinamico View-ViewModel quando lo trasferiamo a ViewModel. Ecco come:

XAML:

<TabControl.ItemContainerStyle> 
       <Style TargetType="TabItem"> 
        <Setter Property="Header" Value="{Binding Header}" /> 
        <Setter Property="Content" Value="{Binding Content}" /> 
       </Style> 
      <TabControl.ItemContainerStyle> 

VM:

public ObservableCollection<TabItem> TabItems { get; set; } 
public MainWindowViewModel() 
     { 
      TabItems = new ObservableCollection<TabItem> 
      { 
       new TabItem{Content = new TabAView() {DataContext = new TabAViewModel()}, Header = "Tab A"}, 
       new TabItem{Content = new TabBView(), Header = "Tab B"} 
      }; 
     } 

Possiamo anche fare uso di delegati di azione per ritardare e richiamare l'inizializzazione dei TabItems solo su Tab SelectionChangedEvent. Ciò consente di risparmiare molta memoria se le viste UserControl hanno molti elementi dell'interfaccia utente.