Ayoub.A
Ayoub.A

Reputation: 2113

WPF: TabControl with multiple DataTemplates

I have a TabControl with multiple DataTemplate. the first DataTemplate will be used for search reasons and the second will be for displaying items obtained from that search. My XAML code will be as follows:

 <UserControl.Resources>
    <!--First template-->
    <DataTemplate>
        <!-- I will have a DataGrid here-->
    </DataTemplate>

    <!--Second template-->
    <DataTemplate >
         <!-- I will have details of one item of the DataGrid-->
    </DataTemplate>
</UserControl.Resources>


<TabControl ItemsSource="{Binding }"/>

What I want to accomplish is that in the TabControl the first tab will contain the first DataTemplate (the search template) and when I double click on one row of my DataGrid, a tab will be added with the details of that row (in other words a tab with the second template).

Since I am using MVVM, I thought of creating two UserControls, one for each template and then catch the double click event, but after this I don't know how to add a tab since now my search template is a UserControl seperated from the one that contains the TabControl.

So how do I do this?

UPDATE:

As I read the answers I think I wasn't very clear in stating the problem. My problem is how to add tabs with the second template, by catching double click events from the first template. I don't have any problem in adding the two templates independently.

Upvotes: 1

Views: 4282

Answers (3)

Liero
Liero

Reputation: 27360

There are two options: Use datatemplate selector, or use implicit datatemplates and different types for each tabitem.

1. DataTemplateSelector:

public ObservableCollection<TabItemVM> Tabs { get; private set; }

public MainVM()
{
    Tabs = ObservableCollection<TabItemVM>
    {
        new TabItemVM { Name="Tab 1" },
    };
}

void AddTab(){
   var newTab = new TabItemVM { Name="Tab 2" };
   Tabs.Add(newTab);
   //SelectedTab = newTab; //you may bind TabControl.SelectedItemProperty to viewmodel in order to be able to activate the tab from viewmodel
}

public class TabItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate Tab1Template { get; set; }
    public DataTemplate Tab2Template { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var tabItem = item as TabItemVM;
        if (tabItem.Name == "Tab 1") return Tab1Template;
        if (tabItem.Name == "Tab 2") return Tab2Template;
        return base.SelectTemplate(item, container);
    }
}
<local:TabItemTemplateSelector
     x:Key="TabItemTemplateSelector"
     Tab1Template="{StaticResource Tab1Template}" 
     Tab2Template="{StaticResource Tab2Template}" />

2. Implicit Data Templates:

public class MainVM : ViewModelBase
{
    public ObservableCollection<TabItemVM> Tabs { get; private set; }

    public MainVM()
    {
        Tabs = new ObservableCollection<TabItemVM>
        {
            new Tab1VM(),
        };
    }

    void AddTab()
    {
        var newTab = new Tab2VM()
        Tabs.Add(newTab);
       //SelectedTab = newTab; 
    }
}

public class TabItemBase
{
    public string Name { get; protected set; }
}

public class Tab1VM : TabItemBase
{
    public Tab1VM()
    {
        Name = "Tab 1";
    }
}

public class Tab2VM : TabItemBase
{
    public Tab2VM()
    {
        Name = "Tab 2";
    }
}
<UserControl.Resources>
   <!--First template-->
   <DataTemplate DataType="local:Tab1VM">
       <!-- I will have a DataGrid here-->
   </DataTemplate>

   <!--Second template-->
   <DataTemplate DataType="local:Tab2VM">
       <!-- I will have details of one item of the DataGrid-->
   </DataTemplate>
</UserControl.Resources>

Upvotes: 1

GazTheDestroyer
GazTheDestroyer

Reputation: 21261

If you're going to do this with MVVM, your tab control should be bound to some ObservableCollection in your VM, and you just add and remove VM's to the collection as needed.

The VMs can be any type you like and your DataTemplates will show the correct view in the tab just like any other view, so yes, create two UserControls for the two views.

public class MainVM
{
    public ObservableCollection<object> Views { get; private set; }

    public MainVM()
    {
        this.Views = new ObservableCollection<object>();
        this.Views.Add(new SearchVM(GotResults));
    }

    private void GotResults(Results results)
    {
        this.Views.Add(new ResultVM(results));
    }
}

Upvotes: 1

CurtisHx
CurtisHx

Reputation: 758

Rather can creating two UserControls, you can create and use a DataTemplateSelector in order to switch different DataTemplates in.

Basically, create a new class that inhereits from DataTemplateSelector and override the SelecteTemplate method. Then declare an instance of it in the XAML (much like a value converter), and then apply it to ContentTemplateSelector property of the TabControl.

More info can be found here.

Upvotes: 2

Related Questions