ComboBox中显示的当前值

时间:2015-07-14 18:48:42

标签: mvvm wpf-controls caliburn.micro

当ComboBox中的项目是数据库中的自定义对象时,我似乎无法在ComboBox中显示当前选定的值。我把以下测试ViewModel和View放在一起。 SimpleWidgets和ObjectWidgets按预期运行。 CodeWidgets(从数据库中检索为自定义' Code'对象的列表)从不显示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; }
}

TestView.xaml是:

<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和ObjectWidgets显示所选值,并在下拉列表中包含所有值。 CodeWidgets为空,但下拉列表中包含所有值。我错过了什么?

2 个答案:

答案 0 :(得分:3)

WPF的ComboBox通过引用将SelectedItem与ItemsSource中的那些进行比较,在您的情况下,new Code(2707)的实例与内存中的实例不完全相同(new Code().Get("UPFLTY").Result).ToList()

避免这种情况的最常见方法是在具有通用对象类型的内容上使用SelectedValueSelectedValuePath

例如,

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

另一种解决方案是确保将SelectedItem设置为ItemsSource中的一个项目,而不是该项目的新实例。

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

第三种解决方案(通常不建议)是覆盖对象的.Equals,以便将项目与引用之外的其他内容进行比较

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

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

请注意,如果你走这条路,你也应该覆盖.GetHashCode()

答案 1 :(得分:1)

SelectedItem 中的实例必须存在于 ItemsSource中。

从您的代码中

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

您可以看到SelectedCodeWidget设置为Code的新实例,该实例不在CodeWidgets中。

答案只是执行以下操作:

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

FindCodeByDERP是您编写的一种方法,用于搜索CodeWidgets中的实例,并返回最强 2707 的实例。不管它是什么意思。我的意思是,你有一个代码 UPFLTY 但是你创建另一个传入 2707 的实例......这没有任何意义。呀。