WPF 数据绑定与组合框的分步介绍






4.89/5 (35投票s)
一组循序渐进的示例,引导您完成使用数据绑定和组合框(ComboBox)的工作。
引言
本文将教您如何使用数据绑定与 ComboBox
。文章将通过以下示例进行讲解:
- 显示一个
string
值并绑定到另一个string
值,所有绑定都在 XAML 中完成。ComboBox
的项目集合在 App.xaml 的应用程序资源中定义为StaticResource
。 - 显示一个
string
值并绑定到一个enum
值,所有绑定都在 XAML 中完成。ComboBox
的项目集合在代码隐藏文件中定义为一个列表。此外,此技术还提供了一种轻松获取enum
的友好可翻译名称的方法。这两个示例将涵盖如何让数据绑定与
ComboBox
协同工作的基本知识。
背景
网上有很多文章涵盖了数据绑定的主题。那么为什么要再写一篇呢?这是个好问题。ComboBox
有一些在绑定到 TextBox
等控件时不存在的复杂性。在所有现有的文章中,当我第一次尝试使用 ComboBox
时,我没有找到一篇清楚解释如何绑定 ComboBox
的文章。此外,我发现很多问题都没有得到完整的解答。在最终弄清楚如何让事情顺利工作之后,我决定分享我的发现。数据绑定与 ComboBox
的主要区别在于,实际上需要设置 4 个绑定。本文将一步一步地向您展示如何让这 4 个数据绑定与 ComboBox
一起工作。
在开始使用 ComboBox
之前,我建议您先阅读并理解数据绑定的基础知识。Josh Smith 在 CodeProject 上发表了几篇关于这个主题的出色文章。其中,WPF 导览 - 第三部分(数据绑定),非常出色地解释了数据绑定的基础知识。另一篇,一步步迈向 WPF 数据绑定,引导您完成使用 TextBox
进行数据绑定的过程。在尝试掌握 ComboBox
的数据绑定之前,理解这些文章中的基础知识非常重要。
演示应用程序中的示例
本文将在两个独立的示例中涵盖数据绑定与 ComboBox
的重要要点。第二个示例建立在第一个示例的基础上,所以请务必查看两个示例以全面理解此主题。
数据绑定组合框示例 #1
这个例子:
- 显示一个
string
值并绑定到一个string
值。 - 所有绑定都在 XAML 中完成。
ComboBox
的项目集合在 App.xaml 文件中定义为应用程序资源。- 注意:
ComboBox
下方的TextBlock
绑定到与ComboBox
相同的属性,以证明数据绑定正在工作。当您在ComboBox
中选择一个新值时,数据对象将被更新,它将发送属性更改通知,TextBlock
将收到属性更改通知并也会被更新。
在查看 ComboBox
的绑定之前,让我们看看我们将用什么来填充它。首先,我们创建三个 ComboBoxItemString
类型(这是此项目中定义的类)的对象数组。ValueString
属性设置为:Red
、Green
和 Blue
。此集合在 App.xaml 文件中的应用程序资源中定义为 StaticResource
,如下所示:
<Application.Resources>
<x:Array x:Key="ColorListString" Type="local:ComboBoxItemString"/>
<local:ComboBoxItemString ValueString = "Red" />
<local:ComboBoxItemString ValueString = "Green"/>
<local:ComboBoxItemString ValueString = "Blue"/>
</x:Array>
</Application.Resources>
现在让我们看看上面使用的 ComboItemString
类。它在这个项目中是这样定义的:
namespace ComboBoxDataBindingExamples
{
/// This class provides us with an object to fill a ComboBox with
/// that can be bound to string fields in the binding object.
public class ComboBoxItemString
{
public string ValueString { get; set; }
}
}
你无法找到比这个类更简单的了。它只有一个名为 ValueString
的 public
属性,类型为 string
。那么它为什么是必需的呢?
事情变得有趣了,请仔细阅读。为了让数据绑定正确工作,您需要一个“属性”来绑定。如果我们有一个 string
数组,我们会绑定到哪个属性?没有任何属性。string
类上唯一的属性是 'Length
',而我们不想绑定到它。这是我最初尝试绑定 ComboBox
时感到困惑的问题之一。为了让事情更加混乱,如果您不使用数据绑定,您可以使用 string
数组来填充 ComboBox
列表。之所以有效,是因为调用了 ToString
方法来获取对象的显示值。这可以,但是当您尝试绑定到它时,它就不起作用了。
我将重复这一点,因为它很重要:为了让数据绑定工作,您必须绑定到对象上的“属性”。ComboBoxItemString
类为我们提供了 'ValueString' 属性以供绑定。
现在让我们看看 XAML 文件中的 ComboBox
定义。这是:
<ComboBox ItemsSource="{StaticResource ColorListString}"
DisplayMemberPath="ValueString"
SelectedValuePath="ValueString"
SelectedValue="{Binding ColorString}" />
ComboBox
有四个属性被设置。让我们逐一查看它们。
ItemsSource
- 绑定到我们上面在 App.xaml 文件中定义的应用程序资源 'ColorListString
' 的static
资源数组。此项目列表用于填充ComboBox
的Items
集合。此集合用于生成下拉列表中显示的项。DisplayMemberPath
- 绑定到ItemsSource
列表中的ComboBoxItemString
对象的ValueString
属性。当从下拉列表中选择一项时,这就是显示给用户的价值。SelectedValuePath
- 绑定到ItemsSource
列表中的ComboBoxItemString
对象的ValueString
属性。当从下拉列表中选择一项时,这是用于获取值以设置SelectedItem
值的属性。SelectedValue
- 使用属性绑定 "{Binding ColorString}
" 进行绑定。当列表中选择一项时,这是数据对象上将被设置为SelectedValuePath
属性返回的值的属性。
查看上面的绑定,您可能会认为 DisplayMemberPath
和 SelectedValuePath
是多余的,因为它们绑定到相同的属性,但事实并非如此。在下一个示例中,您将看到我们利用了这些属性可以绑定到两个不同值的这一事实。敬请期待。
但是仍然缺少两部分。您知道是什么吗?其中之一是我们还没有定义我们要绑定的数据对象,另一个是我们还没有设置 DataContext
。所有数据绑定都基于绑定到对象的属性。DataContext
必须设置为包含您要绑定属性的对象。
那么我们绑定到哪个对象呢?让我们来看看。其余部分在代码隐藏文件中完成。这是:
using System.Windows;
namespace ComboBoxDataBindingExamples
{
public partial class Example1Window : Window
{
// Object to bind the combobox selections to.
private ViewModelString viewModelString = new ViewModelString();
public Example1Window()
{
// Set the data context for this window.
DataContext = viewModelString;
// Display the window
InitializeComponent();
}
}
}
难道这就是完整的代码隐藏文件吗?是的,除了注释,就是这样。这个文件只做了几件事。让我们逐一看看。
- 它有一个
private
成员viewModelString
对象,它被赋值给ViewModelString
类的新实例。 DataContext
被设置为该类的一部分的viewModelString
成员。这意味着ComboBox
的SelectedValue
属性绑定将绑定到ViewModelString
类上名为 'ColorString
' 的属性。
好的,但是 ViewModelString
对象是什么样的呢?这是最后一块,再坚持一下。我们知道它必须有一个名为 'ColorString
' 的 public
属性,否则我们的绑定将不起作用。这是整个 ViewModelString
类。
using System.ComponentModel;
namespace ComboBoxDataBindingExamples
{
/// Class used to bind the combobox selections to. Must implement
/// INotifyPropertyChanged in order to get the data binding to
/// work correctly.
public class ViewModel : INotifyPropertyChanged
{
/// Need a void constructor in order to use as an object element
/// in the XAML.
public ViewModel()
{
}
private string _colorString = "";
/// String property used in binding examples.
public string ColorString
{
get { return _colorString; }
set
{
if (_colorString != value)
{
_colorString = value;
NotifyPropertyChanged("ColorString");
}
}
}
#region INotifyPropertyChanged Members
/// Need to implement this interface in order to get data binding
/// to work properly.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
此类包含以下项:
- 一个
void
构造函数,以便该类可以在 XAML 中用作对象元素。 - 一个名为 '
ColorString
' 的string
属性,用于将数据绑定到ComboBox
。 - 一个
NotifyPropertyChanged
属性,它对于让您的绑定工作是必需的。
就是这样。这并不难,不是吗。
现在我们将在此示例的基础上进行扩展,添加一些额外的技巧。
数据绑定组合框示例 #2
这个例子:
- 显示一个
string
值并绑定到一个enum
值。 - 所有绑定都在 XAML 中完成。
ComboBox
的项目集合在代码隐藏文件中定义为一个列表。- 此技术还提供了一种轻松获取
enum
的友好可翻译名称的方法。 - 注意:
ComboBox
下方的TextBlock
绑定到与ComboBox
相同的属性,以证明数据绑定正在工作。当您在ComboBox
中选择一个新值时,数据对象将被更新,它将发送属性更改通知,TextBlock
将收到属性更改通知并也会被更新。
就像在第一个示例中一样,我们需要创建一个对象数组来在 ComboBox
中显示。这次,我们将在代码隐藏文件中创建列表,因为它引入了处理绑定时的不同技巧。我们稍后将更详细地介绍这一点。代码如下:
// Set up the collection properties used to bind the ItemsSource
// properties to display the list of items in the dropdown lists.
// The string values are loaded from the resource file which can
// be translated into other languages.
ColorListEnum = new List<ComboBoxItemColor>()
{
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Red,
ValueColorString = Properties.Resources.RedText },
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Green,
ValueColorString = Properties.Resources.GreenText },
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Blue,
ValueColorString = Properties.Resources.BlueText },
};
正如您所见,我们在这个列表中使用的是与第一个示例不同的对象。让我们看看上面使用的 ComboBoxItemColor
类。它在这个项目中是这样定义的:
namespace ComboBoxDataBindingExamples
{
/// This class provides us with an object to fill a ComboBox with
/// that can be bound to 'ViewModelEnum.Colors' enum fields in the binding
/// object while displaying a string values in the to user in the ComboBox.
public class ComboBoxItemColor
{
public ViewModelEnum.Colors ValueColorEnum { get; set; }
public string ValueColorString { get; set; }
}
}
与上一个示例一样,这是一个非常简单的类。该类有两个名为 ValueColorString
(类型 string
)和 ValueColorEnum
(类型 ViewModelEnum.Colors
)的 public
属性。由于我们想显示一个 string
值并绑定到一个 enum
值,因此我们需要这两个属性。
现在让我们看看 XAML 文件中的 ComboBox
定义。这是:
<ComboBox ItemsSource="{Binding ColorListEnum}"
DisplayMemberPath="ValueColorString"
SelectedValuePath="ValueColorEnum"
SelectedValue="{Binding ViewModelEnum.ColorEnum}" />
您注意到这些绑定与第一个示例相比有什么不同吗?有一些重要的区别。让我们逐一查看它们。
ItemsSource
- 使用属性绑定 "{Binding ColorListEnum}
" 进行绑定。在前面的示例中,我们将其绑定到了static
资源。DisplayMemberPath
- 绑定到ItemsSource
列表中的ComboBoxItemEnum
对象的ValueColorString
属性。与上一个示例类似。SelectedValuePath
- 绑定到ComboBoxItemString
对象的ValueColorEnum
属性,在ItemsSource
列表中。这与上一个示例不同。我们正在绑定一个不同于DisplayMemberPath
的属性。此绑定将SelectedItem
设置为enum
值,而显示值是string
值。这解释了为什么有两个属性。SelectedValue
- 使用属性绑定 "{Binding ViewModelEnum.ColorEnum}
" 进行绑定。乍一看,这可能看起来与第一个示例相似,但有一个重要的区别。您看到了吗?在此示例中,我们绑定到一个属性(ColorEnum
)的属性(ViewModelEnum
),但为什么呢?答案与我们的ItemsSource
绑定更改以及我们的DataContext
更改有关,请继续阅读。
就像在第一个示例中一样,其余部分在代码隐藏文件中完成。这是:
using System.Windows;
using System.Collections.Generic;
namespace ComboBoxDataBindingExamples
{
public partial class Example2Window : Window
{
// Collection property used to fill the ComboBox with a list
// of ComboBoxItemColor objects that contain colors options.
public List<ComboBoxItemColor> ColorListEnum { get; set; }
// Object to bind the combobox selections to.
public ViewModelEnum ViewModelEnum { get; set; }
private ViewModelEnum viewModelEnum = new ViewModelEnum();
public Example2Window()
{
// Set the property to be used for the data binding to and from
// the ComboBox's.
ViewModelEnum = viewModelEnum;
// Set up the collection properties used to bind the ItemsSource
// properties to display the list of items in the dropdown lists.
// The string values are loaded from the resource file which can
// be translated into other languages.
ColorListEnum = new List<ComboBoxItemColor>()
{
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Red,
ValueColorString = Properties.Resources.RedText },
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Green,
ValueColorString = Properties.Resources.GreenText },
new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Blue,
ValueColorString = Properties.Resources.BlueText },
};
// Set the data context for this window.
DataContext = this;
// Init the window
InitializeComponent();
}
}
}
这个类与第一个示例中的类大不相同。让我们逐一看看。
ColorListEnum
- 此属性是ItemsSource
绑定的属性。它取代了StaticResource
。有时能够绑定到在代码隐藏中定义的集合会很有用。您可以通过这种方式进行操作。请注意,这是一个属性而不是数据成员,这使得绑定成为可能。ViewModelEnum
-SelectedValue
属性通过此属性绑定到ColorEnum
属性。请注意,SelectedValue
绑定设置为 "{Binding ViewModelEnum.ColorEnum}
"。在这种情况下,我们绑定到一个属性的属性。viewModelEnum
- 这是上面属性设置为的数据成员。请记住,您不能直接绑定到数据成员。ColorListEnum
- 初始化为一个包含三个ComboBoxItemColor
对象的List
。这等同于第一个示例中的static
资源。DataContext
- 设置为这个窗口。
等等。在第一个示例中,DataContext
被设置为视图模型类。我们不能在这里这样做吗?不行。您能弄清楚为什么吗?这是因为我们没有将 ItemsSource
绑定到 static
资源。感到困惑了吗?我第一次尝试这个的时候也是如此。
这是数据绑定和 ComboBox
中最令人困惑的部分之一。让我们慢慢地逐步分解。对于 ComboBox
或其他任何控件,您只有一个 DataContext
。这意味着(如果您的 ItemsSource
绑定到代码隐藏属性)您的 ComboBox
的 DataContext
必须包含两个属性供您的 ComboBox
绑定。第一个属性用于您的 ItemsSource
集合(在本例中为 ColorListEnum
),第二个属性用于您的 SelectedValue
属性(在本例中为 ViewModelEnum
属性上的 ColorEnum
属性)。这是将 ComboBox
与 TextBox
等简单控件绑定时的重要区别。
现在我们来看看 ViewModelEnum
类。这是它的全部内容:
using System.ComponentModel;
namespace ComboBoxDataBindingExamples
{
public class ViewModelEnum : INotifyPropertyChanged
{
/// Enum used by the combobox and the view model.
public enum Colors
{
Red = 1,
Green = 2,
Blue = 3,
}
/// Need a void constructor in order to use as an object element
/// in the XAML.
public ViewModelEnum()
{
}
private ViewModelEnum.Colors _colorEnum = ViewModelEnum.Colors.Red;
/// ViewModelEnum.Colors Enum property used in binding examples.
public ViewModelEnum.Colors ColorEnum
{
get { return _colorEnum; }
set
{
if (_colorEnum != value)
{
_colorEnum = value;
NotifyPropertyChanged("ColorEnum");
}
}
}
#region INotifyPropertyChanged Members
/// Need to implement this interface in order to get data binding
/// to work properly.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
与第一个示例相比,这里最大的区别在于该类包含我们想存储在视图模型中的 enum
。如果 enum
在一个单独的类中定义,也可以使用相同的技术。
就是这样。现在您已经掌握了关于数据绑定和 ComboBox
的所有必要知识。
Using the Code
我包含了包含运行这些示例所需的所有源代码的 Visual Studio 2010 项目。如果您只想运行它,我也包含了应用程序。
历史
- 第一版