Current value displayed in ComboBox

2019-09-03 15:22发布

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?

2条回答
聊天终结者
2楼-- · 2019-09-03 15:35

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 and SelectedValuePath on something that has a generic object type instead.

For example,

<ComboBox x:Name="CodeWidgets" 
          SelectedValue="{Binding SelectedCodeId}" 
          SelectedValuePath="Id">

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.

SelectedCodeWidget = CodeWidgets.FirstOrDefault(() => p.Id == 2707);

And the third solution, not usually recommend, is to override the .Equals of your object so it compares the item by something other than reference

public override bool Equals(object obj) 
{ 
    if (obj == null || !(obj is Code)) 
        return false; 

    return ((Code)obj).Id == this.Id); 
}

Note that you should probably also overwrite .GetHashCode() if you go this route too.

查看更多
Juvenile、少年°
3楼-- · 2019-09-03 15:46

The instance that is in SelectedItem must exist within ItemsSource.

From your code

//Code filled ComboBox
CodeWidgets = (new Code().Get("UPFLTY").Result).ToList();
SelectedCodeWidget = new Code(2707); // THIS is where you bugged!

You can see that SelectedCodeWidget is set to a new instance of Code, one that is not in CodeWidgets.

The answer is simply to do the following:

//Code filled ComboBox
CodeWidgets = (new Code().Get("UPFLTY").Result).ToList();
var selectedCode = FindCodeByDERP(CodeWidgets, 2707); // MAKE THIS METHOD
SelectedCodeWidget = selectedCode;

Where FindCodeByDERP is a method you write that searches through the instances in CodeWidgets 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.

查看更多
登录 后发表回答