How to change TabControl tab in WPF without breaking MVVM pattern

My Windows WPF has a TabControl that displays content on different tabs. Clicking on the button below executes the method through the ICommand / Binding interface. The called method generates text that is intended to be displayed on the second tab.

Application mockup

How to switch to the second tab when a button is pressed without violating the MVVM template?

I tried to associate the TabItem.IsSlected property with something in my ViewModel, but I wanted to use other tabs (tab1).

Any thoughts?

+7
source share
5 answers

I found it myself.

The key is two-way binding. When the button is DisplayXamlTab property is DisplayXamlTab true. The IsSelected attribute IsSelected bound to this variable. if another tab is clicked, the binding will set the DisplayXamlTab property to false.

Note: UpdateSourceTrigger=PropertyChanged also very important.

Code below:

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 # Property:

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

if you intend to use MVVM, you will create two dependency properties in the code:

  • ObservableCollection<ItemType> Items;
  • ItemType MySelectedItem;

Then bind the TabSontrol ItemsSource property to Elements and bind the SelectedItem property to MySelectedItem

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

If you want to change the selected tab, just update the dependecy property MySelectedItem

+12
source

Although this question is quite old and already answered well, I thought I'd add this additional answer to demonstrate an alternative way to change the selected TabItem in TabControl . If you have a presentation model for each TabItem , then it may be useful to have the IsSelected property in it to determine if it is selected or not. This can be associated with this IsSelected property IsSelected property using the TabItem.IsSelected property:

 <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> 

Now you can change the selected TabItem from the parent view model as follows:

 MenuItems[0].IsSelected = true; 

Note that since this property is data bound to the TabItem.IsSelected property, calling this ...:

 MenuItems[1].IsSelected = true; 

... infact also automatically sets the MenuItems[0].IsSelected to false . therefore, if the view model you are working with has the IsSelected property set to true, then you can be sure that its associated view is selected in TabControl .

+2
source

You can create a binding between the view model and the TabControl.SelectedIndex property - that is, 0 selects the first TabItem , 1 selects the second, etc.

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

(alternatively, depending on how you configured the settings, you can bind to SelectedItem ...)

+1
source

You will probably want to use some kind of β€œ Event Aggregator ” (ie the Messenger class in MVVM Light) to broadcast some kind of β€œnavigation” message. Your view, TabControl, can listen to a specific message and go to Tab2 when it receives the message.

Alternatively, you can bind the SelectedItem TabControl property to your ViewModel and simply call CurrentTab = MySecondTabViewModel from within your virtual machine. This is the approach recommended by @HighPoint in the comments on OP, but I'm not a fan; See below. Another caveat to this approach is in that you need to be familiar with DataTemplates , since you will need to display a view for each displayed Model ViewModel.

I personally like the first approach, because I do not consider it the "responsibility" of the ViewModel to handle tab navigation. If you simply notify your view when the data changes in your ViewModel, you let the View decide whether to change the tabs.

0
source