views:

849

answers:

4

I have a TabControl whose items are bound to an ObservableCollection:

<TabControl ItemsSource="{Binding MyObservableCollection}" />

The tabs are added and removed as expected as items are added and removed from the collection. However, the SelectedItem reverts to -1 (meaning there is no selected tab) whenever the collection is empty. Then, when an item is added, the SelectedItem stays at -1 and the new tab is not selected.

How do I make the TabControl select the new tab whenever an item is added to the empty collection?

A: 

you're best bet is to probably overwrite the "OnTabAdded" functionality to check if a new one (first one) is added and then setting the SelectedItemIndex to 0;

since you are using ObservableCollection, you know when your collection changes, so I'd subscribe to the changed event form the collection and check the number of items in it.

Roel
I already tried setting the SelectedIndex to 0 in the CollectionChanged event handler and it had no effect - perhaps my handler was being called before the event reached the TabControl.
GraemeF
+5  A: 

There might be an easier way, but you could hook the collection changed event on the ObservableCollection in your VM and set the SelectedItem property to the new item (assuming you have the selected item bound to a property on the VM).

Steven Robbins
+1 Doing this with VM and Binding is *the* way to go.
kek444
I would use SelectedItem rather than index, but it's more of a personal thing.
Graeme Bradbury
Works fine with SelectedItem but not with SelectedIndex. Still, mission accomplished!
GraemeF
@Graeme - I did say SelectedItem, not index.. sounds like you are disagreeing with me :-)
Steven Robbins
It'd be nice to know why SelectedItem works but SelectedIndex doesn't - any ideas?
GraemeF
+1  A: 

If you are looking for a pure MVVM implementation then, add a Index property to the ViewModel and on the CollectionChanged you can set Index=0 if there is no items inside. And in the XAML you can bind that Index as below

<TabControl ItemsSource="{Binding MyObservableCollection}" SelectedIndex="{Binding Index}" />
Jobi Joy
That's exactly what I initially did, but I think I was handling the event before the TabControl got it so it had no effect. I'll give it another go - maybe I got something wrong!
GraemeF
Make sure your Index property setter raises the propertyChanged Event
Jobi Joy
This is by far the best solution :) I wish I could get it to the top ...
Johan
+1  A: 

What you can do is to subscribe for TabControl.ItemContainerGenerator.StatusChanged event and if the status is ContainersGenerated and the SelectedIndex of TabControl is -1, then to make the SelectedIndex of TabControl 0;

// peopleCollection is an ObservableCollection<Person>
People peopleCollection = new People();
public Window1()
{
    InitializeComponent();
    // MyTabControl is an instance of TabControl
    MyTabControl.ItemsSource = peopleCollection;
    MyTabControl.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
}

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
    if((sender as ItemContainerGenerator).Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated && MyTabControl.SelectedIndex == -1)
    {
     MyTabControl.SelectedIndex = 0; 
    }
}

There are 3-rd party solutions that has this functionality out of the box. Telerik's RadTabControl selects the first item whenever the collection changes its state from empty to "containing single item".

Try the demo here: http://demos.telerik.com/silverlight/#TabControl/AddingAndRemovingTabs

Note: It is a SL demo, but it works the same in WPF.

Kiril