【问题标题】:Set SelectedItem of ComboBox from object从对象设置 ComboBox 的 SelectedItem
【发布时间】:2016-04-21 15:46:42
【问题描述】:

我正在 Visual Studio 2015 中构建一个 MVVM Light WPF 应用程序,并使用实体框架 6 (EF) 提供数据。我有一个ComboBox,它显示了某人需要进行药物测试的原因,它看起来像这样:

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

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();
        }
    }
}

我有一个数据服务类,它包含以下代码来获取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);
    }
}

视图模型使用以下代码填充ComboBox:

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

ComboBox 的数据正确;但是,当应用程序启动时,它没有选择正确的值——加载时显示为空白。 SelectedItem (ReasonsForTestVm) 也是该类类型 ReasonForTestViewModel 并从数据库中填充此人的一项。我已逐步检查代码以确保 ReasonsForTestVm 具有正确的数据,并且确实如此。

这是ReasonsForTestVm 的属性:

public ReasonForTestViewModel ReasonForTestVm
{
    get
    {
        return _reasonForTestVm;
    }

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

我在这里做错了什么?我快要疯了!

更新:对于上面属性中的混淆名称,我们深表歉意。固定。

【问题讨论】:

  • ItemsSource="{Binding ReasonsForTest}" -- 什么是ReasonsForTest?是ReasonForTestViewModel的集合吗?我们能看到那个和ReasonsForTestVm 属性的声明吗?你说“ReasonsForTest 类是这样的”,但是你有一个ReasonForTestViewModel 的定义。是不是打错字了?
  • SelectedItem 应该始终是 ItemsSource 的实例。如果 SelectedItem 中的实例不在 ItemsSource 中,则 UI 不会按预期更新。
  • 不,不一样的类型。仔细阅读:ItemsSource 中的 instance 必须在绑定到 SelectedItem 的集合中找到。例如,如果 SelectedItem 绑定到 public Items[] Foo { get; } = new[]{ new Item(), new Item() };,则必须将 Foo 中的项目之一用于 SelectedItem:SelectedItem = Foo[0];。如果您执行SelectedItem = new Item();,即使它们是等效的, UI 也不会按预期运行,因为在 ItemsSource 中找不到 SelectedItem 中的实例——它相当于实例之一,但它不是那个实例。
  • @Will,现在我明白了:所以SelectedItem 必须是填充 ComboBox 的 OC 的确切实例之一。现在它终于点击了!所以,我必须在ItemsSource OC 中搜索应该选择的那个,然后将那个传递给SelectedItem。
  • 是的,尝试一下,看看这是否是您的问题。抱歉,没有太多时间检查您的代码,但我认为这可能是问题所在。

标签: c# wpf entity-framework mvvm combobox


【解决方案1】:

任何扩展 Selector 的 WPF 项控件(例如 ComboBox 和 ListBox)都有两个经常结合使用的属性:ItemsSource 和 SelectedItem。

当您将集合绑定到 ItemsSource 时,这些项目的表示会显示在 UI 中。每个表示都绑定到在绑定到ItemsSource 的集合中找到的实例。例如,如果您使用 DataTemplate 来创建该表示,您会在每个中发现 DataContext 将是集合中的这些实例之一。

当您选择其中一种表示时,SelectedItemproperty 现在会保存集合中绑定到该表示的实例。

这可以通过用户与 UI 的交互来完美运行。但是,在与这些控件进行交互时,以编程方式有一个重要的警告。

将这些属性绑定到视图模型中的相似属性是一种非常常见的模式。

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;}
}

绑定到

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

如果您尝试以这种方式手动更新所选项目...

muhViewModel.MuhSelectedItem = new Item(2);

用户界面不会改变。选择器看到ItemsSource 已更改,是的,但它在ItemsSource 集合中找不到该实例。它不知道一个值为 2 的 Item 实例与任何其他具有相同值的 Item 是等价的。所以它什么也不做。 (这对于真正发生的事情来说有点简单。你可以退出 JustDecompile 并自己看看。它在那里变得非常复杂。)

在这种情况下,您应该做的是更新SelectedItem,在绑定到ItemsSource 的集合中找到一个实例。在我们的示例中,

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

旁注,在调试会话中跟踪实例时,使用 Visual Studio 的 Make Object ID 功能会有所帮助。

【讨论】:

    猜你喜欢
    • 2019-02-18
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2014-05-30
    相关资源
    最近更新 更多