理解 SelectedValue、SelectedValuePath、SelectedItem 和 DisplayMemberPath + 演示
梳理这些属性的混淆之处,并提供一个演示应用程序
项目使用 VS2012 构建,目标为 .NET 4。
目录
引言
我看到这个问题经常出现,所以想提供一个一站式参考,帮助那些想弄明白的人解决这个问题。
快速概览 -> 截图
他们说一图胜千言,所以这里有一张图
我认为一个演示胜过千张图片,所以请随意下载代码并亲自尝试一下。
额外阅读 -> 文字解释
这不是一个新话题,如果你看看 这里、这里、这里 或官方 MSDN 页面 这里,就能很容易地看到。(请注意,在撰写本文时,官方 MSDN 上的评分是 4 条评论中有 0 条认为有帮助)。
SelectedItem
:此属性将返回列表/组合框/容器中当前选定的项。如你所见,这是一个 Object (因为我的列表包含对象)。如果你的 List/Combobox/etc. 包含字符串列表,它将是字符串。如果包含 int,它将是 int。
SelectedValuePath
:设置此属性将使 SelectedValue
属性返回此处选择的属性的值。在我们的示例中,选择 "ShapeColor
" 将使 SelectedValue
只返回颜色,而不是整个形状对象。
注意:您在此处将属性名设置为字符串。请查看下方演示代码中的示例以获取代码。
SelectedValue
:如果你只需要对象的一部分,请设置上面的属性,你将在此处获得该属性的值。请注意,如果未使用 SelectedValuePath
,则此属性等同于使用 SelectedItem
。
DisplayMemberPath
:将其设置为对象的某个属性,当选中该类时,GUI 将显示该属性,而不是显示类名或你的类 ToString()
方法 (你应该始终提供该方法。查看此 书籍的目录 的第 5 项,第 1 章,或向下滚动阅读全文 : )。
Using the Code
我希望保持内容尽可能简单和简短,同时又能提供足够的信息来引起兴趣。我使用了一个简单的 XAML 文件和一些代码隐藏,总共大约有 200 行代码 (包括空格和一些注释)。
MainWindow.xaml
包含一个 DockPanel
,底部有一个页脚,以及一个 StackPanel
,它将填满窗口 (默认情况下,最后一个子元素会这样做)。
由于在此示例中我没有使用 MVVM,所以我通过给 Window 命名来将事物绑定在一起,然后在 Binding ElementName
中引用该名称。path
将指向代码隐藏文件中的匹配属性。
Window x:Class="SelectedValue_and_SelectedItem.MainWindow"
... Name="SelectionFun" >
<ListBox Name="SourceListBox"
ItemsSource="{ Binding ElementName=SelectionFun, Path=ShapeCollection}" />
这涵盖了第一部分,创建对象并将其绑定到我们的列表,以便您可以选择一个形状。
第二部分包含几个 ComboBox
,您可以在其中选择要绑定/查看的属性,以及一些标签,它们将显示实际选择的内容。我还将网格的一部分绑定到形状的颜色,以提供一些额外的视觉反馈。
ComboBox
es 的外观如下
<ComboBox ...
ItemsSource="{ Binding ElementName=SelectionFun, Path=PropertiesList}"
SelectionChanged="DisplayMemberPathCmbx_SelectionChanged" />
标签很简单,所以我们继续。
MainWindow.xaml.cs - 代码隐藏
我使用的对象结构是一个简单的 MyShape
,如下所示
public class MyShape
{
public string ShapeType { get; set; }
public string ShapeColor { get; set; }
public int ShapeSides { get; set; }
}
一个名为 GetShapesList()
的方法将使用类似以下的结构填充我们的形状列表
return new ObservableCollection<MyShape> {
new MyShape{ShapeType = "Circle", ShapeColor = "Blue", ShapeSides = 0 },
new MyShape{ShapeType = "Triangle", ShapeColor = "Yellow", ShapeSides = 3 }, ... }
(虽然边是形状的实际边,但颜色只是我添加的随机颜色。)
当涉及到 PropertiesList
时,事情变得有趣起来,它填充如下
private static ObservableCollection<PropertyObject> GetPropertiesList()
{
ObservableCollection<PropertyObject> return_collection =
new ObservableCollection<PropertyObject>
{ new PropertyObject {PropertyName = "", PropertyType = "Reset to default"} };
var propertiesInfos = typeof(MyShape).GetProperties();
foreach (var propertyInfo in propertiesInfos)
{
return_collection.Add(new PropertyObject
{ PropertyName = propertyInfo.Name,
PropertyType = propertyInfo.PropertyType.Name
});
}
return return_collection;
}
PropertyObject
是一个简单的类,用于保存我们正在处理的属性的 Name
和 Type
(两者都是 string
)。
public class PropertyObject
{
public string PropertyName { get; set; }
public string PropertyType { get; set; }
}
首先,我们会添加一个空的,所以当它被选中时,它将把绑定“重置”为默认值。
然后,我们将使用反射来查找 MyShape
类中的所有属性,以便我们可以从 ComboBox
中选择它们。随意添加更多属性,或将此方法通用化,使其接受一个 Class
作为参数,然后传递你自己的自定义 Class
来查看它的运行效果。
SelectionChanged
事件简单地根据所选内容设置 ListBox
源属性 (我们在 XAML 中称之为 SourceListBox
)。例如
private void DisplayMemberPathCmbx_SelectionChanged
(object sender, SelectionChangedEventArgs e) {
// Get the value
ComboBox cmbx = (ComboBox)sender;
PropertyObject prop_ob = ((PropertyObject)cmbx.SelectedItem);
string name = prop_ob.PropertyName;
// Actual setting happens here
SourceListBox.DisplayMemberPath = name;
}
就这样!下载代码并尝试一下,看看它的效果。 :)
关注点
我通常更倾向于 MVVM,但我想让代码简短,所以我选择了代码隐藏的方法。
请注意使用反射动态获取属性及其类型,以及我们如何通过使用名称将 XAML 绑定到我们的属性。
历史
- 2013 年 10 月 21 日:初始发布
欢迎留下评论、反馈和/或提问。