2
votes

As a new in WPF and MVVM light, I am struggling to apply the MVVM pattern in a TabControl. I will give you an example of what I am trying to achieve.

TabOne xaml and its view model

<UserControl x:Class="TestTabControl.TabOne"
             xmlns:local="clr-namespace:TestTabControl"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="tab one ..." FontWeight="Bold" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</UserControl>

//TabOne ViewModel
class TabOne : ViewModelBase
{
    public string TabName
    {
        get
        {
            return "TabOne";
        }
    }
}

TabTwo xaml and its viewmodel

<UserControl x:Class="TestTabControl.TabTwo"
             xmlns:local="clr-namespace:TestTabControl"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="tab two ..." FontWeight="Bold" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</UserControl>

//TabTwo ViewModel
class TabTwo : ViewModelBase
{
    public string TabName
    {
        get
        {
            return "TabTwo";
        }
    }
}

and finally the MainWindow xaml and its viewmodel

<Window x:Class="TestTabControl.MainWindow"
        xmlns:local="clr-namespace:TestTabControl"
        mc:Ignorable="d"
        Title="Test Tab Control" MinWidth="500" Width="1000" Height="800">
    <TabControl ItemsSource="{Binding TabViewModels}" >
        <TabControl.ItemTemplate >
            <!-- header template -->
            <DataTemplate>
                <TextBlock Text="{Binding TabName}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                ?????????
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Window>


//MainWindow ViewModel 
class MainWindowViewModel : ViewModelBase
{
    private ObservableCollection<ViewModelBase> _tabViewModels;

    public MainWindowViewModel()
    {
        _tabViewModels = new ObservableCollection<ViewModelBase>();
        TabViewModels.Add(new TabOne());
        TabViewModels.Add(new TabTwo());
    }

    public ObservableCollection<ViewModelBase> TabViewModels
    {
        get
        {
            return _tabViewModels;
        }
        set  // is that part right?
        {
            _tabViewModels = value;
            RaisePropertyChanged(() => TabViewModels);
        }
    }
}

What am I supposed to write in the DataTemplate? Can I pass both usercontrols for TabOne and TabTwo in this DataTemplate in order to get the view for each tab I click? Or do I need to write another DataTemplate?

1
@AlexPaven that didn't solve my problem. It's not the same issue! ...I changed my question.gts13
The question I referenced gives ample details but ok, maybe I didn't understand what exactly the issue is. What are you trying to accomplish exactly? What's the property that's supposed to be the contents of the tab control? If you had another property on each tab viewmodel, you could bind that as the content.Alex Paven
the tab headers are updated correctly when I run the app. But I don't know how to update the content of the tab too. How can I bind the xaml of each usercontrol in the tab content?gts13
See this property? msdn.microsoft.com/en-us/library/… you can associate a DataTemplate to a type. When a content control (like the TabControl) is bound to an object (ItemsSource's contents, in this case), it looks for a DataTemplate that matches the object's type. So, to keep things easy, each tab page should be bound to an object of a different type (as required) and each corresponding UserControl should be placed in a DataTemplate (<TabControl.Resources>...) tagged with the apporopriate {x:Type ...}user1228

1 Answers

3
votes

You may already knew the answer by now. But for the benefits of other people, what you need to do is:

    <Grid Margin="10">
      <Grid.Resources>
            <DataTemplate DataType="{x:Type local:TabOne}">
               <local:UserControlOne/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:TabTwo}">
               <local:UserControlTwo/>
            </DataTemplate>
      </Grid.Resources>
      <TabControl Margin="10" 
         ItemsSource="{Binding TabViewModels}">
      </TabControl>
   </Grid>

Please note that, your UserControl for TabOne ViewModel is also named TabOne. I changed it to UserControlOne. Same applies to UserControlTwo.