Here is a little example project I made to allow the tabitem header to be of a usercontrol and tabitem content to be of another usercontrol. It allows for adding and removing tabitems in the same way internet explorer functions. I have also included a flag button next to the close button on each tab item that you can toggle.
This is a full MVVM application written in VB.Net.
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Namespace ViewModel
Public Class TabControlVM
Implements INotifyPropertyChanged
#Region "Properties"
''Holds collection of tab items
Private _myTab As ObservableCollection(Of Model.MyTab) = Nothing
Public Property MyTabCollection As ObservableCollection(Of Model.MyTab)
Get
Return _myTab
End Get
Set(ByVal value As ObservableCollection(Of Model.MyTab))
_myTab = value
OnPropertyChanged("MyTabCollection")
End Set
End Property
''Selected tab item index
Private _selectedIndex As Integer = 0
Public Property SelectedIndex As Integer
Get
Return _selectedIndex
End Get
Set(ByVal value As Integer)
_selectedIndex = value
OnPropertyChanged("SelectedIndex")
End Set
End Property
#End Region
#Region "Relay Commands"
Private _addTab As RelayCommand = Nothing
Public ReadOnly Property AddTabCommand() As ICommand
Get
If _addTab Is Nothing Then
Dim commandAction As New Action(Of Object)(AddressOf Me.AddTab)
_addTab = New RelayCommand(commandAction)
End If
Return _addTab
End Get
End Property
Private _removeTab As RelayCommand = Nothing
Public ReadOnly Property RemoveTabCommand() As ICommand
Get
If _removeTab Is Nothing Then
Dim commandAction As New Action(Of Object)(AddressOf Me.RemoveTab)
_removeTab = New RelayCommand(commandAction)
End If
Return _removeTab
End Get
End Property
#End Region
#Region "Constructor"
''' <summary>
''' <para>Creates a new obeservable collection with tab items for tab control.
''' Uses usercontrol for tab item header and content.</para>
''' </summary>
''' <remarks></remarks>
Public Sub New()
''Create a MyTab collection (tabitems)
_myTab = New ObservableCollection(Of Model.MyTab)
''Create tabitem header object
Dim tabHeaderObj = New TabHeaderAddUC
tabHeaderObj.DataContext = Me
''Create the Add Tab content object
Dim tabContentObj As New TabContentAddUC
tabContentObj.DataContext = Me
''Add to collection
_myTab.Add(New Model.MyTab(tabHeaderObj, tabContentObj, 0))
End Sub
#End Region
#Region "Add Tab"
''' <summary>
''' <para>Method which creates a new tabitem object and adds it to MyTab collection.</para>
''' </summary>
''' <param name="obj">Object of command parameter from view.</param>
''' <remarks></remarks>
Private Sub AddTab(ByVal obj As Object)
''Checks the highest MyTab.Index which will be used when assigingin
''a new tab item (index + 1)
Dim i As Integer = 0
For Each tb As Model.MyTab In MyTabCollection
If tb.Index > i Then i = tb.Index
Next
''Create tabitem header object
Dim tabHeaderObj = New TabHeaderUC
''Enable if you want to explicitly set view model class here instead of in the view
''-----------------------------------------------------------------------------
tabHeaderObj.DataContext = New ViewModel.TabHeaderVM With {.HeaderText = "Tab item " & i}
''-----------------------------------------------------------------------------
''Create tabitem content object
Dim tabContentObj As New TabContentMyContentUC
tabContentObj.DataContext = Me
''Have the add tab on the left side
''-----------------------------------------------------------------------------
''Add to collection
'MyTabCollection.Add(New Model.MyTab(tabHeaderObj, tabContentObj, i + 1))
''-----------------------------------------------------------------------------
''Have the add tab on the right side
''-----------------------------------------------------------------------------
''Insert to collection
MyTabCollection.Insert(i, New Model.MyTab(tabHeaderObj, tabContentObj, i + 1))
''-----------------------------------------------------------------------------
''Set the highest tab item to visible
SelectedIndex = i
End Sub
#End Region
#Region "Remove Tab"
''' <summary>
''' <para>Removes the tab item at specified index.</para>
''' </summary>
''' <param name="obj">Object of command parameter from view containing the TabItem.</param>
''' <remarks></remarks>
Private Sub RemoveTab(ByVal obj As Object)
''Gets the tabitem MyTab.Index from tabitem Tag and
''removes the item at this location from the collection
Dim tabItemObj = DirectCast(obj, TabItem)
''Have the add tab on the left side
''-----------------------------------------------------------------------------
'If Not tabItemObj.Tag = 0 Then MyTabCollection.RemoveAt(tabItemObj.Tag)
''-----------------------------------------------------------------------------
''Have the add tab on the right side
''-----------------------------------------------------------------------------
If Not tabItemObj.Tag = 0 Then MyTabCollection.RemoveAt(tabItemObj.Tag - 1)
''-----------------------------------------------------------------------------
''Rebuild the MyTab.Index to match tabitem index
Dim j As Integer = 1
For Each item As Model.MyTab In _myTab
If Not item.Index = 0 Then
item.Index = j
j += 1
End If
Next
''Set the highest tab item to visible
SelectedIndex = j
End Sub
#End Region
#Region "INotifyPropertyChanged"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal PropertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
#End Region
End Class
End Namespace
Imports System.ComponentModel
Namespace Model
Public Class MyTab
Implements INotifyPropertyChanged
#Region "Properties"
''Tab item header usercontrol
Private _header As UserControl = Nothing
Property Header As UserControl
Get
Return _header
End Get
Set(ByVal value As UserControl)
_header = value
OnPropertyChanged("Header")
End Set
End Property
''Tab content user control
Private _content As UserControl = Nothing
Property Content As UserControl
Get
Return _content
End Get
Set(ByVal value As UserControl)
_content = value
OnPropertyChanged("Content")
End Set
End Property
''Tab item index in tabcontrol
Private _indexObj As Integer = 0
Property Index As Integer
Get
Return _indexObj
End Get
Set(ByVal value As Integer)
_indexObj = value
OnPropertyChanged("Index")
End Set
End Property
#End Region
#Region "Constructor"
''' <summary>
''' <para>Constructor accepting two user controls as parameters for header and content.</para>
''' </summary>
''' <param name="h">UserControl containing header information.</param>
''' <param name="c">UserControl containing content information.</param>
''' <param name="i">Integer representing an artificial index of the tabitems.</param>
''' <remarks></remarks>
Public Sub New(ByVal h As UserControl, ByVal c As UserControl, ByVal i As Integer)
Try
Header = h
Content = c
Index = i
Catch ex As Exception
Throw New Exception("Error in MyTab constructor.")
End Try
End Sub
#End Region
#Region "INotifyPropertyChanged"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal PropertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
#End Region
End Class
End Namespace
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Namespace ViewModel
Public Class TabHeaderVM
Implements INotifyPropertyChanged
#Region "Properties"
''Set flag image
Private _imageSource As String = ""
Public Property ImageSource As String
Get
Return _imageSource
End Get
Set(ByVal value As String)
_imageSource = value
OnPropertyChanged("ImageSource")
End Set
End Property
''Header text
Private _headerText As String = ""
Public Property HeaderText As String
Get
Return _headerText
End Get
Set(ByVal value As String)
_headerText = value
OnPropertyChanged("HeaderText")
End Set
End Property
#End Region
#Region "Relay Commands"
Private _SetTabItemFlagImageCommand As RelayCommand = Nothing
Public ReadOnly Property SetTabItemFlagImageCommand() As ICommand
Get
If _SetTabItemFlagImageCommand Is Nothing Then
Dim commandAction As New Action(Of Object)(AddressOf Me.SetTabItemFlagImage)
_SetTabItemFlagImageCommand = New RelayCommand(commandAction)
End If
Return _SetTabItemFlagImageCommand
End Get
End Property
#End Region
#Region "Constructor"
''' <summary>
''' <para></para>
''' </summary>
''' <remarks></remarks>
Public Sub New()
End Sub
#End Region
#Region "Set Flag Visibility"
Private Sub SetTabItemFlagImage()
If ImageSource = "" Then
ImageSource = "/Images/16x16/Flag-red.png"
ElseIf ImageSource = "/Images/16x16/Flag-red.png" Then
ImageSource = "/Images/16x16/Flag-gray.png"
ElseIf ImageSource = "/Images/16x16/Flag-gray.png" Then
ImageSource = ""
End If
End Sub
#End Region
#Region "INotifyPropertyChanged"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal PropertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
#End Region
End Class
End Namespace