65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (35投票s)

2011年12月18日

CPOL

11分钟阅读

viewsIcon

545724

downloadIcon

14292

一组循序渐进的示例,引导您完成使用数据绑定和组合框(ComboBox)的工作。

引言

本文将教您如何使用数据绑定与 ComboBox。文章将通过以下示例进行讲解:

  1. 显示一个 string 值并绑定到另一个 string 值,所有绑定都在 XAML 中完成。ComboBox 的项目集合在 App.xaml 的应用程序资源中定义为 StaticResource
  2. 显示一个 string 值并绑定到一个 enum 值,所有绑定都在 XAML 中完成。ComboBox 的项目集合在代码隐藏文件中定义为一个列表。此外,此技术还提供了一种轻松获取 enum 的友好可翻译名称的方法。

    这两个示例将涵盖如何让数据绑定与 ComboBox 协同工作的基本知识。

Intro.png

背景

网上有很多文章涵盖了数据绑定的主题。那么为什么要再写一篇呢?这是个好问题。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 将收到属性更改通知并也会被更新。

Example1.png

在查看 ComboBox 的绑定之前,让我们看看我们将用什么来填充它。首先,我们创建三个 ComboBoxItemString 类型(这是此项目中定义的类)的对象数组。ValueString 属性设置为:RedGreenBlue。此集合在 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; }
    }
}

你无法找到比这个类更简单的了。它只有一个名为 ValueStringpublic 属性,类型为 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 资源数组。此项目列表用于填充 ComboBoxItems 集合。此集合用于生成下拉列表中显示的项。
  • DisplayMemberPath - 绑定到 ItemsSource 列表中的 ComboBoxItemString 对象的 ValueString 属性。当从下拉列表中选择一项时,这就是显示给用户的价值。
  • SelectedValuePath - 绑定到 ItemsSource 列表中的 ComboBoxItemString 对象的 ValueString 属性。当从下拉列表中选择一项时,这是用于获取值以设置 SelectedItem 值的属性。
  • SelectedValue - 使用属性绑定 "{Binding ColorString}" 进行绑定。当列表中选择一项时,这是数据对象上将被设置为 SelectedValuePath 属性返回的值的属性。

查看上面的绑定,您可能会认为 DisplayMemberPathSelectedValuePath 是多余的,因为它们绑定到相同的属性,但事实并非如此。在下一个示例中,您将看到我们利用了这些属性可以绑定到两个不同值的这一事实。敬请期待。

但是仍然缺少两部分。您知道是什么吗?其中之一是我们还没有定义我们要绑定的数据对象,另一个是我们还没有设置 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();
        }
    }
}

难道这就是完整的代码隐藏文件吗?是的,除了注释,就是这样。这个文件只做了几件事。让我们逐一看看。

  1. 它有一个 private 成员 viewModelString 对象,它被赋值给 ViewModelString 类的新实例。
  2. DataContext 被设置为该类的一部分的 viewModelString 成员。这意味着 ComboBoxSelectedValue 属性绑定将绑定到 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 将收到属性更改通知并也会被更新。

Example2.png

就像在第一个示例中一样,我们需要创建一个对象数组来在 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 绑定到代码隐藏属性)您的 ComboBoxDataContext 必须包含两个属性供您的 ComboBox 绑定。第一个属性用于您的 ItemsSource 集合(在本例中为 ColorListEnum),第二个属性用于您的 SelectedValue 属性(在本例中为 ViewModelEnum 属性上的 ColorEnum 属性)。这是将 ComboBoxTextBox 等简单控件绑定时的重要区别。

现在我们来看看 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 项目。如果您只想运行它,我也包含了应用程序。

历史

  • 第一版
© . All rights reserved.