2013-03-06 11 views
7

My Windows WPF contiene un controllo TabControl che visualizza il contenuto su diverse schede. Un clic sul pulsante in basso esegue un metodo tramite l'interfaccia ICommand/Binding. Il metodo chiamato genera del testo che deve essere visualizzato nella seconda scheda.Come modificare la scheda da TabControl in WPF senza violare il pattern MVVM

Application Mockup

Come posso passare alla seconda linguetta sul pulsante scatto senza violare il modello MVVM?

Ho provato a collegare la proprietà TabItem.IsSelected a qualcosa nel mio ViewModel ma volevo usare anche le altre schede (tab1).

Qualche idea?

+4

Si prega di non chiamare una 'finestra 'WPF una" forma ". Questo è un insulto. –

+0

lol @HighCore - Ho letteralmente detto la stessa identica cosa a un collega qualche giorno fa ... – JerKimball

+3

Per favore guarda [questo] (http://stackoverflow.com/questions/15209870/dynamically-updating-tabcontrol-content- at-runtime/15210593 # 15210593) spiegazione di cosa sia 'TabControl' e come dovrebbe essere trattato, da un punto di vista MVVM. –

risposta

11

L'ho scoperto da solo.

La chiave è una rilegatura a due vie. Quando si fa clic sul pulsante, viene impostata la proprietà DisplayXamlTab true. L'attributo IsSelected è associato a questa variabile. se si fa clic su un'altra scheda, il binding imposterà la proprietà DisplayXamlTab su false.

Nota: UpdateSourceTrigger=PropertyChanged è anche molto importante

Codice viene qui di seguito:

XAML:

 <TabItem Header="XAML" IsSelected="{Binding DisplayXamlTab, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
      <Grid Background="#FFE5E5E5"> 
       <TextBox x:Name="TxtXamlOutput" IsReadOnly="True" Text="{Binding XamlText, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> 
      </Grid> 
     </TabItem> 

C# Proprietà:

private bool displayXamlTab; 
public bool DisplayXamlTab 
{ 
    get { return this.displayXamlTab; } 
    set 
    { 
     this.displayXamlTab = value; 
     this.RaisePropertyChanged("DisplayXamlTab"); 
    } 
} 
+0

Come si ottiene RaisePropertyChanged? –

+0

RaisePropertyChanged è l'implementazione MVVMLight dell'interfaccia INotifyPropertyChanged. – Joel

+0

Oh, mi stavo chiedendo - thx –

0

Probabilmente vorrai utilizzare una sorta di modello "Event Aggregator" (ad esempio la classe Messenger in MVVM Light) per trasmettere una sorta di messaggio di "navigazione". La tua vista - il TabControl - può ascoltare il messaggio specifico e navigare fino a Tab2 quando il messaggio viene ricevuto.

In alternativa, è possibile associare la proprietà "SelectedItem" di TabControl a ViewModel e chiamare semplicemente CurrentTab = MySecondTabViewModel dall'interno della VM. Questo è il approach raccomandato da @HighPoint nei commenti all'OP, ma non sono un fan; vedi sotto. Un'altra avvertenza a questo approccio è che è necessario avere familiarità con DataTemplates, poiché sarà necessario mappare una vista su ciascun ViewModel che si visualizza.

Personalmente mi piace il primo approccio, perché non ritengo che sia una "responsabilità" del ViewModel per gestire la navigazione delle schede. Se si avvisa semplicemente la propria Vista quando i dati cambiano nel ViewModel, si consente alla Vista di decidere se vuole o meno modificare le schede.

+0

Questo non è necessario e aggiunge un sovraccarico non necessario e riduce la manutenibilità. Si prega di guardare il link nel mio commento. –

+0

@HighCore - guarda i miei commenti sopra. Non sono un fan dell'uso del binding "SelectedItem". – BTownTKD

+0

Non sono d'accordo. Ma tu hai un punto valido. Per inciso, DataTemplates è un must per qualsiasi sviluppatore WPF. Da un altro punto di vista più astratto, si può pensare che l'impostazione del "widget attivo" sia effettivamente una responsabilità della VM. –

1

È possibile creare un legame tra il modello di visualizzazione e la proprietà TabControl.SelectedIndex - vale a dire, 0 seleziona il primo TabItem, 1 seleziona il secondo, ecc

<TabControl DataContext="..." SelectedIndex="{Binding SomeVmProperty}" ... 

(in alternativa, a seconda di come hai impostato le cose, si potrebbe legare contro SelectedItem ...)

+2

Perché questo non funziona per me? Modifiche alle proprietà, Notifys, ma l'interfaccia utente non cambia mai. –

12

se si sta andando nella direzione MVVM si sta andando a creare due proprietà di dipendenza nel codice dietro:

  • ObservableCollection<ItemType> Items;
  • ItemType MySelectedItem;

Quindi, associare la proprietà TabControl ItemsSource alle Elementi e associare la proprietà SelectedItem per MySelectedItem

<TabControl ItemsSource="{Binding Items}" 
     SelectedItem="{Binding MySelectedItem, Mode=TwoWay}"> 
<TabControl.ItemTemplate> 
    <DataTemplate> 
     <... here goes the UI to display ItemType ... > 
    </DataTemplate> 
    </TabControl.ItemTemplate> 
</TabControl> 

Quando si desidera modificare la scheda selezionata, semplicemente aggiornare la proprietà di dipendenza MySelectedItem

2

Anche se questa domanda è piuttosto vecchio e ben ho già risposto, pensavo di aggiungere questa risposta aggiuntiva per dimostrare un modo alternativo di modificare il TabItem selezionato in un TabControl. Se si dispone di un modello di visualizzazione per ogni TabItem, può essere utile avere una proprietà IsSelected al suo interno per determinare se è selezionata o meno. E 'possibile i dati legano questa proprietà IsSelected con la proprietà TabItem.IsSelected utilizzando la proprietà ItemContainerStyle:

<TabControl ItemsSource="{Binding MenuItems}" TabStripPlacement="Top"> 
    <TabControl.ItemTemplate> 
     <DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}"> 
      <StackPanel Orientation="Horizontal"> 
       <Image Source="{Binding ImageSource}" Margin="0,0,10,0" /> 
       <TextBlock Text="{Binding HeaderText}" FontSize="16" /> 
      </StackPanel> 
     </DataTemplate> 
    </TabControl.ItemTemplate> 
    <TabControl.ContentTemplate> 
     <DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}"> 
      <ContentControl Content="{Binding ViewModel}" /> 
     </DataTemplate> 
    </TabControl.ContentTemplate> 
    <TabControl.ItemContainerStyle> 
     <Style TargetType="{x:Type TabItem}"> 
      <Setter Property="IsSelected" Value="{Binding IsSelected}" /> 
     </Style> 
    </TabControl.ItemContainerStyle> 
</TabControl> 

È ora possibile modificare la TabItem selezionato dalla vista del modello genitore come questo:

MenuItems[0].IsSelected = true; 

Nota che a causa questa proprietà è dati associati alla proprietà TabItem.IsSelected, chiamando questo ...:

MenuItems[1].IsSelected = true; 

... imporrà inoltre automaticamente la proprietà MenuItems[0].IsSelected su false. quindi se il modello di vista con cui si sta lavorando ha la proprietà IsSelected impostata su true, allora si può essere sicuri che la relativa vista sia selezionata in TabControl.

Problemi correlati