How to create a new instance of the view for a tab item in the WPF TabControl

By default the WPF TabControl will not create a new instance of the content control inside the ContentTemplate for each Item (Tab).  All it does is just change the DataContext.  This is fine if all your state is on your ViewModel.  But I had a problem as I was hosting WinForm controls inside the tabs.  So I really want a new control for each tab.  I don’t have that many tabs.  So I’m not worried about virtualization, well yet.

The simplest thing I could think of was use a Content control, set the content to the DataContext (thus it will change each time you switch tabs) and use a Converter to return the correct view.

public class NewViewForEachInstanceConverter : IValueConverter
{
    private readonly IDictionary<object, object> _views = new Dictionary<object, object>();

    public Type ViewType { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;
        object view;
        _views.TryGetValue(value, out view);
        if (view != null) return view;

        view = Activator.CreateInstance(ViewType);
        _views.Add(value, view);

        return view;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

<DockPanel>
    <DockPanel.Resources>
        <Infrastructure:NewViewForEachInstanceConverter 
            x:Key="NewControlForEachInstanceConverter" ViewType="{x:Type Views:SomeView}" />
    </DockPanel.Resources>
   .....
    <TabControl ItemsSource="{Binding ThingsIWantToBeTabs}">
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentControl Content="
                    {Binding Converter={StaticResource NewControlForEachInstanceConverter}}" />
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</DockPanel>

Note:  This implementation here is very simple and doesn’t deal with the fact that later you might well remove tabs.  This will leak because the view / view model will stay in the dictionary.  Not a problem for me yet, I’ll solve it when it becomes one.  Do the simplest thing and all.

I thought I’d share it as I saw a few people having the same problem when I double checked there wasn’t a built in way.  Hope it helps.

Advertisements

About Tom Peplow

C# .Net developer based in London and the South Coast
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s