I'm adding a close button to my tabs using the following guide:
http://www.codeproject.com/Articles/84213/How-to-add-a-Close-button-to-a-WPF-TabItem
This has become a problem because the event uses the 'parent' of the added tab to remove that tab from the tabcontrol. I'm binding the tab control using mvvm, so the parent property is apparently not being set and giving me a null reference exception for the parent when the event tries to remove from it.
Here's the binding so you get the idea:
<TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"/>
Heres where the tabs are being added.
private void AddTab(object tabName)
{
ClosableTab newTab = new ClosableTab();
newTab.Title = "title?";
//newTab.Header = tabName;
TextBox test = new TextBox();
test.Text = "CONTENT (" + tabName + ") GOES HERE";
newTab.Content = test;
Tabs.Add(newTab);
OnPropertyChanged("Tabs");
}
Here is the event where the null reference is taking place:
void button_close_Click(object sender, RoutedEventArgs e)
{
((TabControl)this.Parent).Items.Remove(this);
}
As I see it there are two options:
- try to find another way to remove the tab (without the parent property)
- try to find a way to somehow set the parent property (which cant be done directly, it throws a compiler error)
That doesn't sound like MVVM to me. We work with data, not UI elements. We work with collections of classes that contain all of the properties required to fulfil some requirement and data bind those properties to the UI controls in
DataTemplate
s. In this way, we add UI controls by adding data items into these collections and let the wonderful WPF templating system take care of the UI.For example, you have a
TabControl
that we want to add or removeTabItem
s from... in a proper MVVM way. First, we need a collection of items that can represent eachTabItem
:I'm just using a
DependencyProperty
because I knocked this up in aUserControl
and I'm just using a collection ofstring
s for simplicity. You'll need to create a class that contains all of the data required for the wholeTabItem
content. Next, let's see theTabControl
:We data bind the collection to the
TabControl.ItemsSource
property and we set theTabControl.ItemTemplate
to aResource
namedItemTemplate
. Let's see that now:This
DataTemplate
defines what each item in our collection will look like. For simplicity's sake, ourstring
s are just data bound to theTabItem.Header
property. This means that for each item we add into the collection, we'll now get a newTabItem
with itsHeader
property set to the value of thestring
:Note that I included the
System
XML Namespace Prefix for completeness, but you won't need that because yourDataType
will be your own custom class. You'll need moreDataTemplate
s too. For example, if your custom class had aHeader
property and aContent
property, which was another custom class, let's say calledContent
, that contained all of the properties for theTabItem.Content
property, you could do this:So this would give you
TabItem
s withHeader
s set andContent
that comes fromSomeUserControl
which you could design. You don't need to useUserControl
s, you could just add more UI controls to eitherDataTemplate
. But you will need to add more controls somewhere... and more classes and properties, always remembering to correctly implement the essentialINotifyPropertyChanged
interface.And finally, to answer your question in the proper MVVM way... to remove a
TabItem
, you simply remove the item that relates to thatTabItem
from the collection. Simple... or it would have been if you really had been using MVVM like you claim. It's really worth learning MVVM properly as you'll soon see the benefits. I'll leave you to find your own tutorials as there are many to chose from.UPDATE >>>
Your event handling is still not so MVVM... you don't need to pass a reference of any view model anywhere. The MVVM way is to use commands in the view model. In particular, you should investigate the
RelayCommand
. I have my own version, but these commands enable us to perform actions from data boundButton
s and other UI controls using methods or inlinedelegate
s in the view model (whereaction
andcanExecute
in this example are theCommandParameter
values):So whatever view model has your
Tabs
collection should have anAddTabCommand
and aCloseTabCommand
that add and remove items from theTabs
collection. But just to be clear, for this to work properly, yourClosableTab
class should be a data class and not a UI control class. Use aDataTemplate
to specify it if it is a UI control.You can find out about the
RelayCommand
from this article on MSDN.