4

I have created a tab control and Created the tabItems dynamically, but i dont know how to add controls into the tabItems using MVVM. Could any one help me

devdigital
  • 34,151
  • 9
  • 98
  • 120
Tanya
  • 1,571
  • 5
  • 22
  • 33
  • What do you mean under "add controls into the tabItems using MVVM"? Do you need to add some controls there? Are controls on each tab similar (not content)? – Anatolii Gabuza Jan 06 '12 at 09:29
  • I need to add some controls into the tabPage dynamically using mvvm – Tanya Jan 06 '12 at 10:43
  • @Tanya My solution should allow you to do exactly that. Add a comment if you have any questions. :) – eandersson Jan 06 '12 at 10:46
  • It's not quite right to tell that we are going to dynamically add items to `View` using `MVVM`. Google it: [Dynamically adding UserControls WPF](https://www.google.com/search?q=Dynamically+adding+user+Controls+WPF). There are a lot of answers. – Anatolii Gabuza Jan 06 '12 at 11:02
  • addin controls dynamically has nothing do to with mvvm. can you specify your needs? if you want a tabpage look different in dependence of the datacontext(viewmodel/viewmodel property), you just have to use datatemplates – blindmeis Jan 06 '12 at 12:49

3 Answers3

19

There are a few ways to programmatically add Tab Items in WPF and I am going to show you a simple example on how I deal with this in my application.

First I host a collection of the ViewModels for the TabItems (or Workspaces as I refer to them) in my MainWindowViewModel.cs:

private ObservableCollection<WorkspaceViewModel> _workspaces;

public ObservableCollection<WorkspaceViewModel> Workspaces
{
    get
    {
        if (_workspaces == null)
        {
            _workspaces = new ObservableCollection<WorkspaceViewModel>();
        }
        return _workspaces;
    }
}

Next I add a reference to the various controls in my MainWindow.xaml. This is important as we want to make sure that whenever the collection contains a ViewModel that it displays the appropriate View for that Model.

 <Window.Resources>
        <DataTemplate DataType="{x:Type vm:MyUserControlViewModel}">
            <vw:MyUserControlView/>
        </DataTemplate>
  </Window.Resources>

If you have multiple types of UserControls you simply add them all here like this:

<Window.Resources>
        <DataTemplate DataType="{x:Type vm:FirstUserControlViewModel}">
            <vw:FirstUserControlView/>
        </DataTemplate>
       <DataTemplate DataType="{x:Type vm:SecondUserControlViewModel}">
            <vw:SecondUserControlView/>
        </DataTemplate>
       <DataTemplate DataType="{x:Type vm:ThirdUserControlViewModel}">
            <vw:ThirdUserControlView/>
        </DataTemplate>
  </Window.Resources>

Next we add the TabControl and bind it to our Workspace Collection.

 <TabControl ItemsSource="{Binding Workspaces}"/>

Then I simply add my ViewModels to the Collection to have them show up in the TabControl.

Workspaces.Add(new FirstUserControlViewModel());
Workspaces.Add(new SecondUserControlViewModel());
Workspaces.Add(new ThirdUserControlViewModel());

My WorkspaceViewModel that I base the TabItem collection of is very simple and looks something like this:

public abstract class WorkspaceViewModel : BaseViewModel
{
    public String HeaderText { get; set; }
    public override string ToString()
    {
           return HeaderText;
    }
}

Adding a TabItem:

To create a TabItem you simply create a UserControl and ViewModel like you normally would using WPF and the MVVM pattern.

namespace MyApplication.ViewModel
{
    public class FirstUserControlViewModel : WorkspaceViewModel
    {
        public FirstUserControlViewModel ()
        {
            base.HeaderText = "My First Tab";
        }
    }
}

Next you need to bind a View to your new ViewModel.

    <DataTemplate DataType="{x:Type vm:FirstUserControlViewModel }">
        <vw:FirstUserControlView/>
    </DataTemplate>

Then you create an instance of the ViewModel and add it to the collection in your MainWindowViewModel.

FirstUserControlViewModel firstvm = new FirstUserControlViewModel();
Workspaces.Add(firstvm);

And now the TabItem should show up in your TabControl.

Loading TabItems dynamically using Extensions:

In some cases you might even need to load TabItems from plugins dynamically without the host application first knowing about the TabItem. In these cases you need to have the plugin register the View and ViewModel with the application domain.

This is very easy to do, and actually something I do for one of my MEF based projects. I have an post here, with some additional details as well.

All you need to do is add a Resource Dictionary to your plugin/extension and make sure that the host application loads it once the plugin has been imported.

To show you a fast example I would have a View.xaml in my extensions:

   <ResourceDictionary
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:vw="clr-namespace:MyExtension.Test">

        <DataTemplate DataType="{x:Type vw:TestViewModel}">
            <vw:TestView/>
        </DataTemplate>

    </ResourceDictionary>

I then expose the ResourceDictinary using MEF to the Host like this:

private ResourceDictionary _viewDictionary = new ResourceDictionary();

public ResourceDictionary Dict
{
    get
    {
        return _viewDictionary;
    }
}

_viewDictionary.Source =
                new Uri("/MyExtension.Test;component/View.xaml",
                UriKind.RelativeOrAbsolute);

Last you use Application.Current.Resources.MergedDictionaries.Add to load the View.xaml into the host.

Community
  • 1
  • 1
eandersson
  • 25,781
  • 8
  • 89
  • 110
5

You Dont have to add controls you just have to specify the UserControl.

TabControl has two properties ItemTemplate && Content Template

ItemTemplate is for how the Tab will look where as

ContentTemplate is how the Tab Content will Look... so...

Xaml for the above

            <TabControl Grid.Row="1"
                        ItemsSource="{Binding Path=TabList}"
                        SelectedItem="{Binding Path=SelectedTab,
                                               Mode=TwoWay}"
                 <!--This is How tab will look-->                                   >
                <TabControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Width="20"
                                   Height="20"
                                   Margin="0,0,2,0"
                                   Source="Images\TreeView\yourFavImg.png" />
                            <TextBlock Margin="0,4,0,0"
                                       VerticalAlignment="Center"
                                       FontWeight="Bold"
                                       Text="{Binding Path=TabText}" />
                        </StackPanel>
                    </DataTemplate>
                </TabControl.ItemTemplate>
                <!--This will be the content for the tab control-->
                <TabControl.ContentTemplate>
                    <DataTemplate>
                <!--This User Control will contain the controls you like-->
                        <ViewLayer:YourFavUserControl />
                    </DataTemplate>
                </TabControl.ContentTemplate> 
Community
  • 1
  • 1
Ankesh
  • 4,847
  • 4
  • 38
  • 76
  • Is it possible to add components in the data Template – Tanya Jan 06 '12 at 10:44
  • What exaclty you want to do.... Add controls to a userControl.... DataTemplate fill the `` withy data required. be specific in telling the requirement... and elobrate in your question – Ankesh Jan 06 '12 at 12:19
1

you dont have to add controls if you use mvvm. you just have to create datatemplates for your viewmodel objects you wanna display.

all you need is a contentcontrol/presenter which is bind to your viewmodel and the datatemplate will show what you want.

blindmeis
  • 22,175
  • 7
  • 55
  • 74