我在Visual Studio 2015中使用提供数据的Entity Framework 6(EF)构建MVVM Light WPF应用程序。我有一个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();
}
}
我在这里做错了什么?我快要忘记了!
更新:抱歉,上面的媒体资料名称令人困惑。固定的。
答案 0 :(得分:2)
扩展Selector的任何WPF项控件(例如ComboBox和ListBox)都有两个经常结合使用的属性:SelectedItem
和ItemsSource
。
将集合绑定到ItemsSource
时,UI中会显示这些项目的表示形式。每个表示都绑定到绑定到SelectedItem
的集合中找到的实例。例如,如果您使用DataTemplate来创建该表示,那么您将在每个中找到DataContext将是该集合中的其中一个实例。
当您选择其中一个表示时,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;}
}
属性现在保存绑定到该表示的集合中的实例。
通过用户与UI的交互,这非常有效。但是,与这些控件以编程方式进行交互时,有一个重要的警告。
将这些属性绑定到视图模型中的类似属性是一种非常常见的模式。
<ComboBox ItemsSource="{Binding MuhItems}"
SelectedItem="{Binding MuhSelectedItem}" />
绑定到
muhViewModel.MuhSelectedItem = new Item(2);
如果您尝试以这种方式手动更新所选项目......
ItemsSource
用户界面将不更改。选择器看到ItemsSource
已更改,是的,但它在SelectedItem
集合中找不到该实例。它不知道具有值2的Item的一个实例等同于具有相同值的任何其他Item。所以它什么都不做。 (对于真正发生的事情来说,这有点过于简单。你可以破坏JustDecompile并亲眼看看。在那里真正令人费解。)
在这种情况下,您应该做的是使用绑定到ItemsSource
的集合中找到的实例更新var derp = muhViewModel.MuhItems.FirstOrDefault(x => x.MuhValue == 2);
muhViewModel.MuhSelectedItem = derp;
。在我们的例子中,
luaopen_*
旁注,在跟踪调试会话中的实例时,有助于使用Visual Studio的Make Object ID功能。