I can't seem to get the current selected value to show in the ComboBox when the items in the ComboBox are custom objects from the database. I put together the following test ViewModel and View. SimpleWidgets and ObjectWidgets behave as expected. CodeWidgets (list retrieved from the database as custom 'Code' objects) never displays the SelectedCodeWidget.
public class TestViewModel:BaseTabViewModel
{
private List<int> simpleWidgets;
public List<int> SimpleWidgets
{
get { return simpleWidgets; }
set
{
simpleWidgets = value;
NotifyOfPropertyChange(() => SimpleWidgets);
}
}
private int selectedSimpleWidget;
public int SelectedSimpleWidget
{
get { return selectedSimpleWidget; }
set
{
selectedSimpleWidget = value;
NotifyOfPropertyChange(() => SelectedSimpleWidget);
}
}
private List<Widget> objectWidgets;
public List<Widget> ObjectWidgets
{
get { return objectWidgets; }
set
{
objectWidgets = value;
NotifyOfPropertyChange(() => ObjectWidgets);
}
}
private Widget _selectedObjectWidget;
public Widget SelectedObjectWidget
{
get { return _selectedObjectWidget; }
set
{
_selectedObjectWidget = value;
NotifyOfPropertyChange(() => SelectedObjectWidget);
}
}
private List<ICode> codeWidgets;
public List<ICode> CodeWidgets
{
get { return codeWidgets; }
set
{
codeWidgets = value;
NotifyOfPropertyChange(() => CodeWidgets);
}
}
private Code _selectedCodeWidget;
public Code SelectedCodeWidget
{
get { return _selectedCodeWidget; }
set
{
_selectedCodeWidget = value;
NotifyOfPropertyChange(() => SelectedCodeWidget);
}
}
public TestViewModel()
{
DisplayName = "Test Data";
IsEnabled = true;//control this with permissions
//Simple int comboBox
SimpleWidgets = new List<int> {1, 3, 5, 7, 9};
SelectedSimpleWidget = 7;
//Object filled ComboBox
ObjectWidgets= new List<Widget>();
Widget w = new Widget {Key = 2, Description = "test2"};
ObjectWidgets.Add(w);
w = new Widget { Key = 4, Description = "test4" };
ObjectWidgets.Add(w);
w = new Widget {Key = 6, Description = "test6"};
ObjectWidgets.Add(w);
SelectedObjectWidget = w;
//Code filled ComboBox
CodeWidgets = (new Code().Get("UPFLTY").Result).ToList();
SelectedCodeWidget = new Code(2707);
}
}
public class Widget
{
public int Key { get; set; }
public string Description { get; set; }
}
The TestView.xaml is:
<UserControl x:Class="CAB.DataManager.App.Views.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UniformGrid>
<ComboBox Name="SimpleWidgets"></ComboBox>
<ComboBox Name="ObjectWidgets"
DisplayMemberPath="Description" >
</ComboBox>
<ComboBox x:Name="CodeWidgets">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</UniformGrid>
</UserControl>
SimpleWidgets and ObjectWidgets show the selected value and have all values in the dropdown. CodeWidgets is blank but does have all values in the dropdown. What am I missing?
WPF's ComboBox compares the SelectedItem to the ones in the ItemsSource by reference, and in your case the instance of
new Code(2707)
is not the exact same instance in memory as whatever is in(new Code().Get("UPFLTY").Result).ToList()
The most common way to avoid this is to use
SelectedValue
andSelectedValuePath
on something that has a generic object type instead.For example,
Another solution is to ensure the SelectedItem is set to one of the items in the ItemsSource, and not a new instance of the item.
And the third solution, not usually recommend, is to override the
.Equals
of your object so it compares the item by something other than referenceNote that you should probably also overwrite
.GetHashCode()
if you go this route too.The instance that is in
SelectedItem
must exist withinItemsSource
.From your code
You can see that
SelectedCodeWidget
is set to a new instance ofCode
, one that is not inCodeWidgets
.The answer is simply to do the following:
Where
FindCodeByDERP
is a method you write that searches through the instances inCodeWidgets
and returns the instance which 2707s the hardest. Whatever that means. I mean, you've got a Code UPFLTY yet you create another instance passing in 2707... that makes no sense. Yeah.