Expose a Combined Collection
You can expose a collection in your view model that combines both the collection and the addtional item like below (if you do not modify the collection, you can also use any other enumerable type).
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel()
{
var myTabItemCollection = // ...get the items collection.
var mySummaryTabItem = // ...get the summary item.
TabItems = new ObservableCollection<string>(myTabItemCollection)
{
mySummaryTabItem
};
}
public ObservableCollection<MyTabItemViewModel> TabItems { get; }
// ...other properties, methods, ...
}
Using a Composite Collection
There is a dedicated CompositeCollection
type for combining one or multiple collections and single items in XAML. However, this type has severe shortcommings in terms of data-binding. It does neither derive from FrameworkElement
, nor is it a Freezable
, which makes it very difficult, cumbersome and error-prone to work with. I will present one solution with this type for the sake of completeness. Let's assume this view model:
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<MyTabItemViewModel> TabItems { get; }
public MyTabItemViewModel Summary { get; }
// ...other properties, methods, ...
}
In theory this would be easy if CompositeCollection
would be to data-bindable (this does not work):
<TabControl>
<TabControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding TabItems}" />
<TabItem DataContext="{Binding Summary}"
Header="{Binding}"
Content="{Binding}" />
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
In order to make it work, your can apply various approaches like in these related questions:
As an example, I will use a binding proxy type to enable binding inside CompositeCollection
. It will bind to the DataContext
of the TabControl
and expose it with the Data
property. Since the proxy is a resource, the CompositeCollection
can refer to it as source for binding with StaticResource
.
<TabControl x:Name="TabControl">
<TabControl.Resources>
<local:BindingProxy x:Key="TabControlBindingProxy" Data="{Binding}" />
</TabControl.Resources>
<TabControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Data.TabItems, Source={StaticResource TabControlBindingProxy}}" />
<TabItem DataContext="{Binding Data.Summary, Source={StaticResource TabControlBindingProxy}}"
Header="{Binding}"
Content="{Binding}" />
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
This will also work for multiple collections and single items, but be aware that this and the other approaches from the related questions - although they compile and run just fine - might crash the Visual Studio designer, which is unfortunate. Consequently, I recommend you to take the approach of exposing a combined collection, which is more reliable, easier to comprehend and simple.