WPF ComboBox SelectedItem

Jose picture Jose · Jan 28, 2010 · Viewed 12.9k times · Source

Ok been working with WPF for a while but I need some help.

I have a ComboBox like below:

<TabControl>
    <TabItem Header="1">
        <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
    </TabItem>
    <TabItem Header="2"/>
</TabControl>

Whenever I move away from tab 1 and then come back to it the selection gets removed. I think the reason for that is that the controls get destroyed when they go out of scope and then back in. But in the process of that the SelectedItem becomes null which isn't really what the user wanted, it's an event due to the UI lifecycle.

So I'm wondering what is the best route to take? I'm building this app with MVVM so I could ignore a set call on the MyListSelection Property in my ViewModel but I have ComboBoxes all over the place and don't like modifying my ViewModel for what I consider a bug of WPF.

I could subclass the WPF ComboBox, but there is no SelectedItemChanging event I can only add a handler when SelectedItem changed.

Any ideas?

UPDATE:

Okay, after beating my head against the wall I found out why my problem couldn't get reproduced. If the list item type is a class for some reason the SelectedItem gets set by WPF to null but if it's a value type it doesn't.

here's my test class(VMBase is just an abstract class that implements INotifyPropertyChanged):

public class TestListViewModel : VMBase
{
    public TestListViewModel()
    {
        TestList = new List<TestViewModel>();
        for (int i = 0; i < 10; i++)
        {
            TestList.Add(new TestViewModel(i.ToString()));
        }
    }

    public List<TestViewModel> TestList { get; set; }

    TestViewModel _SelectedTest;
    public TestViewModel SelectedTest
    {
        get { return _SelectedTest; }
        set
        {
            _SelectedTest = value;
            OnPropertyChanged("SelectedTest");
        }
    }
}

public class TestViewModel : VMBase
{
  public string Name {get;set;}
}

So when I change TestList to type int and go back and forth between tabs SelectedItem stays the same. But when it is of type TestViewModel SelectedTest gets set to null when the tabitem goes out of focus.

What's going on?

Answer

Eduardo Laranjeira picture Eduardo Laranjeira · May 7, 2010

I've the exact same problem, and till now I couldn't figure what the problem is. I tested in 4 different machines with the same OS, .Net version and hardware specifications and could reproduce the issue in two of them, in the other ones worked just fine. The workaround I could find that works for me is to define the SelectedItem binding before the ItemsSource. Strangely if I follow this pattern, everything works as expected. That said, you just have to do the following:

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>