Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add controls in the tab item programmatically in wpf with MVVM

Tags:

c#

mvvm

wpf

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

like image 471
Tanya Avatar asked Nov 29 '22 03:11

Tanya


1 Answers

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.

like image 186
eandersson Avatar answered Dec 06 '22 17:12

eandersson