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?
I think what you may be missing here is a TwoWay binding on the SelectedItem. When you bind your ViewModel class which contains the MyList(bound ItemsSource) and MyListSelection(Bond to SelectedItem in your Case) will always have those information even though you went to different tabs. So when you come back to this Tab the MyListSelection will bind back to the ComboBoc.SelectedItem again and you will be good. Try this and let me know.
This behavior by the combobox, should be implemented by the compiler in a better fashion than it is... IE the compiler should check and see if the types for the ItemsSource and the type reference value of the property that the SelectedItem is bound to will EVER return the a value that is comparable
It should warn that you might consider overriding the Equals() and GetHashCode() methods...
Wasted a lot of time on this today !!
I was having the exact same problem with a reference type in my list. The solution was to override Equals() in my TestViewModel so that WPF would be able to do a value equality check (instead of a reference check) between the objects to determine which one is the SelectedItem. Mine happened to have an ID field that was really the identifying feature of a TestViewModel.
I think this could be solved with a simple null check.
This is because ComboBox has a tendency to reset its SelectedIndex when recycled. This simple null check will force it to rebind to the last valid item.
I would recommend checking the bindings. If anything else in your app is changing the selected item or the items source, then your binding will break. You can also look in Visual Studio at the output window to see if there are any errors.
EDITED after change in OP. Hi Jose, I am unable to reproduce the error you mention. So your assumption about the Control being destroyed is wrong. The Combobox behaves as expected with the code behind below even it is now using a reference type. Some other piece of your code must kick in when you change TabItems.