简体   繁体   English

从对象设置ComboBox的SelectedItem

[英]Set SelectedItem of ComboBox from object

I'm building an MVVM Light WPF app in Visual Studio 2015 with Entity Framework 6 (EF) providing the data. 我正在使用提供数据的Entity Framework 6(EF)在Visual Studio 2015中构建MVVM Light WPF应用程序。 I have a ComboBox that displays the reasons why someone needs to take a drug test and it looks like this: 我有一个ComboBox ,显示了有人需要进行药物测试的原因,它看起来像这样:

<ComboBox ItemsSource="{Binding ReasonsForTest}"
    SelectedItem="{Binding Path=ReasonsForTestVm,
                     UpdateSourceTrigger=PropertyChanged}"
    DisplayMemberPath="Description" />

The ReasonsForTest is of type ReasonForTestViewModel class: ReasonsForTest的类型为ReasonForTestViewModel类:

public class ReasonForTestViewModel: ViewModelBase
{
    private int _ReasonForTestId;
    private string _ReasonForTestAbbr;
    private string _description;

    public int ReasonForTestId
    {
        get { return _ReasonForTestId; }
        set
        {
            if (value == _ReasonForTestId) return;
            _ReasonForTestId = value;
            RaisePropertyChanged();
        }
    }

    public string ReasonForTestAbbr
    {
        get { return _ReasonForTestAbbr; }
        set
        {
            if (value == _ReasonForTestAbbr) return;
            _ReasonForTestAbbr = value;
            RaisePropertyChanged();
        }
    }

    public string Description
    {
        get { return _description; }
        set
        {
            if (value == _description) return;
            _description = value;
            RaisePropertyChanged();
        }
    }
}

I have a data service class that contains the following code to fetch the data for the valid values of the ComboBox : 我有一个数据服务类,其中包含以下代码来获取ComboBox的有效值的数据:

public async Task<ObservableCollection<ReasonForTestViewModel>> GetReasonsForTest()
{
    using (var context = new MyEntities())
    {
        var query = new ObservableCollection<ReasonForTestViewModel>
            (from rt in context.ReasonForTests
             orderby rt.description
             select new ReasonForTestViewModel
             {
                 ReasonForTestId = rt.ReasonForTestID,
                 ReasonForTestAbbr = rt.ReasonForTestAbbr,
                 Description = rt.description,
             });
        return await Task.Run(() => query);
    }
}

The view model populates the ComboBox using this: 视图模型使用以下方法填充ComboBox

var dataService = new TestDataService();    
ReasonsForTest = await dataService.GetReasonsForTest();

The ComboBox has the correct data; ComboBox具有正确的数据; however, it's not selecting the correct value when the app starts -- it's showing blank on load. 但是,当应用程序启动时,它没有选择正确的值 - 它在加载时显示为空白。 The SelectedItem ( ReasonsForTestVm ) is also of that class type ReasonForTestViewModel and gets populated from the database with the one item for this person. SelectedItemReasonsForTestVm )也属于类类型ReasonForTestViewModel并从数据库中填充此人员的一个项目。 I've stepped through the code to ensure ReasonsForTestVm has the correct data, and it does. 我已经逐步完成了代码以确保ReasonsForTestVm具有正确的数据,而且确实如此。

Here's the property for ReasonsForTestVm : 这是ReasonsForTestVm的属性:

public ReasonForTestViewModel ReasonForTestVm
{
    get
    {
        return _reasonForTestVm;
    }

    set
    {
        if (Equals(value, _reasonForTestVm)) return;
        _reasonForTestVm = value;
        RaisePropertyChanged();
    }
}

What am I doing wrong here? 我在这做错了什么? I'm about to lose my mind! 我快要疯了!

Update : Sorry for the confusing name in the property above. 更新 :对不起上面的财产令人困惑的名字。 Fixed. 固定。

Any WPF items control that extends Selector (such as ComboBox and ListBox) has two properties that are often used in conjunction: ItemsSource and SelectedItem . 任何WPF项控件扩展Selector (例如ComboBox和ListBox)都有两个经常结合使用的属性: ItemsSourceSelectedItem

When you bind a collection to ItemsSource , a representation of those items are shown in the UI. 将集合绑定到ItemsSource ,UI中会显示这些项的表示形式。 Each one of the representations is bound to an instance found within the collection bound to ItemsSource . 每个表示都绑定到在ItemsSource绑定的集合中找到的实例。 If, for an example, you're using a DataTemplate to create that representation, you'll find within each that the DataContext will be one of those instances from the collection. 例如,如果您正在使用DataTemplate来创建该表示,那么您将在每个内容中找到DataContext将是该集合中的其中一个实例。

When you select one of these representations, the SelectedItem property now holds the instance from the collection that was bound to that representation. 当您选择其中一个表示时, SelectedItem属性现在保存绑定到该表示的集合中的实例。

This works perfectly through user interaction with the UI. 这通过用户与UI的交互完美地工作。 However, there's one important caveat when interacting with these controls programmatically . 但是,在以编程方式与这些控件交互时,有一个重要的警告。

It's a very common pattern to bind these properties to similar properties in your view model. 将这些属性绑定到视图模型中的类似属性是一种非常常见的模式。

public class MuhViewModel
{
    public MuhItems[] MuhItems {get;} = new[]{ new Item(1), new Item(2) };

    // I don't want to show INPC impls in my sample code, kthx
    [SuperSlickImplementINotifyPropertyChangedAttribute]
    public MuhSelectedItem {get;set;}
}

bound to 势必

<ComboBox ItemsSource="{Binding MuhItems}"
          SelectedItem="{Binding MuhSelectedItem}" />

If you try to manually update the selected item this way... 如果您尝试以这种方式手动更新所选项目...

muhViewModel.MuhSelectedItem = new Item(2);

The UI will not change. 用户界面不会改变。 The Selector sees that ItemsSource has changed, yes, but it doesn't find that instance in the ItemsSource collection. Selector看到ItemsSource已更改,是的,但它没有在ItemsSource集合中找到该实例。 It doesn't know that one instance of Item with a value of 2 is equivalent to any other Item with the same value. 它不知道具有值2的Item的一个实例等同于具有相同值的任何其他Item。 So it does nothing. 所以它什么都不做。 (That's a bit simplistic for what really happens. You can bust out JustDecompile and see for yourself. It gets real convoluted down in there.) (对于真正发生的事情来说,这有点过于简单。你可以破坏JustDecompile并亲眼看看。它在那里真正令人费解。)

What you should be doing in this situation is updating SelectedItem with an instance found within the collection bound to ItemsSource . 在这种情况下,您应该做的是使用绑定到ItemsSource的集合中找到的实例更新SelectedItem In our example, 在我们的例子中,

var derp = muhViewModel.MuhItems.FirstOrDefault(x => x.MuhValue == 2);
muhViewModel.MuhSelectedItem = derp;

Side note, when tracking instances within a debug session, it helps to use Visual Studio's Make Object ID feature. 旁注,在调试会话中跟踪实例时,有助于使用Visual Studio的Make Object ID功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM