数据绑定和列表

已完成

Tech logo of U W P and W P F. W P F appears dimmed.

到目前为止,仅已使用数据绑定来显示和编辑一个对象的属性。 在本课中,你将应用数据绑定概念来显示对象集合。 为了简单起见,这些对象是颜色。 说得更清楚点就是,它们是多个 ColorDescriptor 类实例。

1.创建 ColorDescriptor

让我们创建一个类来表示颜色。 右键单击“解决方案资源管理器”中的“DatabindingSample”项目,选择“添加”/“类”,再输入“ColorDescriptor”作为类名。 选择“添加”,以创建此类。

ColorDescriptor 包含两个属性:作为 Windows.UI.Color 对象的颜色本身,以及颜色名称。 它还包含填充这些属性的构造函数、显示颜色名称的 ToString() 方法,以及 R、G 和 B 颜色成分的十六进制值。 下面是整个 ColorDescriptor 类。

using Windows.UI;

namespace DatabindingSample
{
    public class ColorDescriptor : ObservableObject
    {
        public ColorDescriptor(Color color, string name)
        {
            Color = color;
            Name = name;
        }

        public Color Color { get; private set; }

        public string Name { get; private set; }

        public override string ToString()
        {
            return $"{Name} (#{Color.R:X2}{Color.G:X2}{Color.B:X2})";
        }
    }
}

将 ColorDescriptor.cs 文件的默认内容替换为上面的代码。

2.创建 ColorList.xaml 页

为了显示颜色列表,我们将使用新的 XAML 页面。 右键单击“解决方案资源管理器”中的“DatabindingSample”项目,并选择“添加”/“新建项”。 从可选项列表中选择“空白页面”,再输入“ColorList”作为名称。 选择“添加”,以创建页面。

Screenshot that shows Blank Page selected under Visual C Sharp, in the Add New Item dialog box.

3.设置启动页面

现在,如果启动应用,打开的是“MainPage”页面。 由于将使用新建的 ColorList.xaml 页面,因此最好将它用作起始页面。 为此,请打开 App.xaml.cs,并找到负责导航到 MainPage 的代码行。

rootFrame.Navigate(typeof(MainPage), e.Arguments);

MainPage 替换为 ColorList,并验证“ColorList”页面是否是应用的启动页面(按 F5 或选择“调试”/“开始调试”启动应用)。

4.创建用于颜色列表的逻辑

我们将继续采用前面介绍的最佳做法,即为新页单独创建逻辑。 所以,接下来将新建 ColorListLogic 类。

右键单击“解决方案资源管理器”中的“DatabindingSample”项目,选择“添加”/“类”,再输入“ColorListLogic”作为类名。 选择“添加”以创建此类,并将下面的代码粘贴到文件中:

using System.Collections.Generic;
using System.Collections.ObjectModel;

using Windows.UI;

namespace DatabindingSample
{
    public class ColorListLogic : ObservableObject
    {
        public List<ColorDescriptor> LotsOfColors { get; private set; }

        public ColorListLogic()
        {
            LotsOfColors = new List<ColorDescriptor>
            {
               new ColorDescriptor(Colors.Red, "red"),
               new ColorDescriptor(Colors.White, "white"),
               new ColorDescriptor(Colors.Green, "green"),
               new ColorDescriptor(Colors.Yellow, "yellow"),
               new ColorDescriptor(Colors.Blue, "blue"),
               new ColorDescriptor(Colors.Black, "black")
            };

        }
    }
}

ColorListLogic 类非常简单(目前)。 它有 LotsOfColors 属性,即 ColorDescriptor 对象的 List。 在类的构造函数中,列表填充有一些颜色。 就是这样。

5.在 ListBox 中显示颜色

下一步是,在应用中显示颜色。 首先,先让 ColorListLogic 可通过 XAML 进行访问。 打开 ColorList.xaml.cs,并将下面的代码添加到 ColorList 类中:

public ColorListLogic Logic { get; } = new ColorListLogic();

这里使用的语法与前面对 MainPageLogic 使用的相同。 它创建 get-only 属性,并将它的值初始化为新建的 ColorListLogic 对象。

接下来,打开 ColorList.xaml,并在 Grid 元素内添加以下 XAML。

<ListBox ItemsSource="{x:Bind Logic.LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top"/>

其中有趣的是 ItemsSource 属性。 顾名思义,它提供 ListBox 中显示项的源。 它只绑定到 ColorListLogicLotsOfColors 属性。

如果现在运行应用,应该会发现它在 ListBox 中显示颜色! 但看起来不太符合预期。 ListBox 似乎调用了 LotsOfColors 列表中存储的 ColorDescriptorToString() 方法。

Screenshot that shows the Data binding Sample window, with yellow selected.

6.定义项模板

最好有模板可显示 ColorDescriptor.Color 属性中存储的实际颜色及其名称。 如下图所示:

Screenshot of template.

若要在 XAML 中对此进行编码,可以在 StackPanel 中放入有颜色的 RectangleTextBlock

<StackPanel Orientation="Horizontal">
    <Rectangle Width="80" Height="20">
        <Rectangle.Fill>
            <SolidColorBrush Color="Blue"/>
        </Rectangle.Fill>
    </Rectangle>
    <TextBlock Text="blue" Margin="20, 10, 0, 10"/>
</StackPanel>

这就是 XAML 和数据绑定的优势之一。 几乎所有复杂视觉对象所依据的模板都可重新定义。 必须将上面的 StackPanel 放入 DataTemplate 中,才能将它用作模板。 DataTemplate 需要定义 DataType,即可向其应用模板的数据类型。 在此示例中,它是 ColorDescriptor 类。 所以,DataTemplate 如下所示:

<DataTemplate x:DataType="local:ColorDescriptor">
    <!-- template content comes here -->
</DataTemplate>

数据在 ListBox(以及其他许多控件)中的呈现方式受控于它的 ItemTemplate(应设置为 DataTemplate)。 有多种方法可实现此操作。 在本课中,只需使用以下语法,在 ListBox 中定义 DataTemplate 即可:

<ListBox ...>
    <ListBox.ItemsSource>
        <DataTemplate ...>
            ...
        </DataTemplate>
    </ListBox.ItemsSource>
</ListBox>

稍后将会介绍如何将 DataTemplate 定义为资源,从而在多个位置重用它。

现在整个 ListBox 如下所示(如果尚未跟着我一起操作,请将整个 <ListBox> 标记替换为下面的 XAML):

<ListBox ItemsSource="{x:Bind Logic.LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top">
    <ListBox.ItemTemplate>
        <DataTemplate x:DataType="local:ColorDescriptor">
            <StackPanel Orientation="Horizontal">
                <Rectangle Width="80" 
                           Height="20">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="{x:Bind Color}"/>
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Text="{x:Bind Name}" 
                           Margin="20, 10, 0, 10"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

请注意,因为 ListBox 中的每一项都对应于 ColorDescriptor 对象,所以只需在此类的上下文中定义模板内的绑定。 编译器甚至会检查 Logic.LotsOfColors 是否包含 ColorDescriptor 对象,以及 ColorDescriptor.ColorColorDescriptor.Name 是否存在且类型是否正确。

7.运行应用

现在,按 F5 或选择菜单中的“调试”/“开始调试”,以运行应用。 应该会看到色彩缤纷的颜色列表。

Screenshot that shows the Data binding Sample window, with a list of six colors next to rectangles representing the color.

如果在调试模式下启动 XAML 应用,可利用实时 XAML 编辑。 甚至无需停止应用或按保存按钮。 只需更改 XAML,正在运行的应用中就会立即反映大部分更改。 现在就试试。 将数据模板内 RectangleWidthHeight 更改为 30,从而将颜色矩形变为方形。

Screenshot that shows the Data binding Sample window, with a list of six colors next to squares representing the color.

这称为 XAML 热重载,它非常适用于微调应用中的布局和动画。

总结

本课介绍了在 ListBox 中显示多个项的基础知识。 具有类似用途的控件还有其他许多,如 ItemsControlListViewGridView。 但基本原则是相同的:将对象列表(IEnumerableList<>)绑定到 ItemsSource 属性,并将 DataTemplates 定义为控制各个列表项的外观和行为方式。 还可以重新定义这些项的布局,甚至是容器控件本身的外观(尽管这超出了本模块范围)。

请注意,代码从来都不需要处理 ListBox 本身。 它只创建了业务对象集合 (ColorDescriptor),而 XAML 运行时则负责展开每一项的模板。

下一课将介绍如何便于用户从 ListBox 或下拉列表中选择项,并更改代码中的列表内容,以便在 UI 中反映元素添加和删除。

Tech logo of U W P and W P F. U W P appears dimmed.

到目前为止,仅已使用数据绑定来显示和编辑一个对象的属性。 在本课中,你将应用数据绑定概念来显示对象集合。 为了简单起见,这些对象是颜色。 说得更清楚点就是,它们是 ColorDescriptor 类的多个实例。

1.创建 ColorDescriptor

让我们创建类来表示颜色。 右键单击“解决方案资源管理器”中的“DatabindingSampleWPF”项目,选择“添加”/“类”,再输入“ColorDescriptor”作为类名。 选择“添加”,以创建此类。

ColorDescriptor 包含两个属性:作为 System.Windows.Media.Color 对象的颜色本身,以及颜色名称。 它还包含设置这些属性的构造函数、显示颜色名称的 ToString() 方法,以及 R、G 和 B 颜色成分的十六进制值。 下面是整个 ColorDescriptor 类。

using System.Windows.Media;

namespace DatabindingSampleWPF
{
    public class ColorDescriptor : ObservableObject
    {
        public ColorDescriptor(Color color, string name)
        {
            Color = color;
            Name = name;
        }

        public Color Color { get; private set; }

        public string Name { get; private set; }

        public override string ToString()
        {
            return $"{Name} (#{Color.R:X2}{Color.G:X2}{Color.B:X2})";
        }
    }
}

ColorDescriptor.cs 文件的默认内容替换为上面的代码。

2.创建 ColorList.xaml 页

为了显示颜色列表,我们将使用新的 XAML 文件。 右键单击“解决方案资源管理器”中的“DatabindingSampleWPF”项目,并选择“添加”/“新建项”。 从可选项列表中选择“窗口(WPF)”,再输入“ColorList”作为名称。 选择“添加”,以创建页面。

Screenshot of Add New Item dialog box.

3.设置启动 XAML 文件

现在,如果启动应用,打开的是“MainWindow”页面。 由于将使用新创建的 ColorList.xaml 页面,因此最好让它在应用启动时显示。 为此,打开 App.xaml,并找到根 Application 元素的 StratupUri 属性。

StartupUri="MainWindow.xaml"

MainWindow 替换为 ColorList,并验证“ColorList”是否是应用的启动页面(按 F5 或选择“调试”/“开始调试”启动应用)。

Screenshot that shows an empty Color List window.

4.创建用于颜色列表的 DataContext

我们将继续采用前面介绍的最佳做法,即为新 XAML 窗口单独创建 DataContext 类。 所以,我们接下来将创建一个新类,称为 ColorListDataContext

右键单击“解决方案资源管理器”中的“DatabindingSample”项目,选择“添加”/“类”,再输入“ColorListDataContext”作为类名。 选择“添加”以创建此类,并将下面的代码粘贴到文件中:

using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Windows.Media;

namespace DatabindingSampleWPF
{
    public class ColorListDataContext: ObservableObject
    {
        public List<ColorDescriptor> LotsOfColors { get; private set; }

        public ColorListDataContext()
        {
            LotsOfColors = new List<ColorDescriptor>
            {
               new ColorDescriptor(Colors.Red, "red"),
               new ColorDescriptor(Colors.White, "white"),
               new ColorDescriptor(Colors.Green, "green"),
               new ColorDescriptor(Colors.Yellow, "yellow"),
               new ColorDescriptor(Colors.Blue, "blue"),
               new ColorDescriptor(Colors.Black, "black")
            };
        }
    }
}

ColorListDataContext 类非常简单(目前)。 它有 LotsOfColors 属性,即 ColorDescriptor 对象的 List。 在类的构造函数中,列表填充有一些颜色。 就是这样。

5.在 ListBox 中显示颜色

下一步是,在应用中显示颜色。 如前面一样,我们需要在 ColorList.xaml 中创建 ColorListDataContext 类的一个实例,并将它设置为整个窗口的 DataContext。 打开 ColorList.xaml,并紧跟在 <Window ...> 标记后添加下面的代码:

<Window.DataContext>
    <local:ColorListDataContext/>
</Window.DataContext>

此时,需要编译代码,以便 XAML 设计器能够解决新定义的 ColorListDataContext 类。

然后,在 <Grid> 标记内复制以下 XAML 标记:

<ListBox ItemsSource="{Binding LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top"/>

其中有趣的是 ItemsSource 属性。 顾名思义,它提供 ListBox 中显示项的源。 它只绑定到 ColorListDataContextLotsOfColors 属性。

如果现在运行应用,应该会发现它在 ListBox 中显示颜色! 但看起来不太符合预期。 ListBox 似乎调用了 LotsOfColors 列表中存储的 ColorDescriptorToString() 方法。

Screenshot that shows the Color List window with six colors listed.

6.定义项模板

最好有模板可显示 ColorDescriptor.Color 属性中存储的实际颜色及其名称。 如下图所示:

Screenshot fo template.

若要在 XAML 中对此进行编码,可以在 StackPanel 中放入有颜色的 RectangleTextBlock

<StackPanel Orientation="Horizontal">
    <Rectangle Width="80" Height="20">
        <Rectangle.Fill>
            <SolidColorBrush Color="Blue"/>
        </Rectangle.Fill>
    </Rectangle>
    <TextBlock Text="blue" Margin="20, 10, 0, 10"/>
</StackPanel>

这就是 XAML 和数据绑定的优势之一。 几乎所有复杂视觉对象所依据的模板都可重新定义。 必须将上面的 StackPanel 放入 DataTemplate 中,才能将它用作模板:

<DataTemplate>
    <!-- template content comes here -->
</DataTemplate>

数据在 ListBox(以及其他许多控件)中的呈现方式受控于它的 ItemTemplate(应设置为上面的 DataTemplate)。 有多种方法可实现此操作。 在本课中,只需使用以下语法,在 ListBox 中定义 DataTemplate 即可:

<ListBox ...>
    <ListBox.ItemsSource>
        <DataTemplate ...>
            ...
        </DataTemplate>
    </ListBox.ItemsSource>
</ListBox>

稍后将会介绍如何将 DataTemplate 定义为资源,从而在多个位置重用它。

现在整个 ListBox 的标记如下所示(如果尚未跟着我一起操作,请将整个 <ListBox> 元素替换为下面的 XAML):

<ListBox ItemsSource="{Binding LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Rectangle Width="80" 
                           Height="20">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="{Binding Color}"/>
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Text="{Binding Name}" 
                           Margin="20, 10, 0, 10"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

请注意,因为 ListBox 中的每一项都对应于 ColorDescriptor 对象,所以只需在此类的上下文中定义模板内的绑定。

7.运行应用

应该会立即在 Visual Studio 中看到颜色列表。 只是确保一下,现在按 F5 或选择菜单中的“调试”/“开始调试”,以运行应用。

Screenshot that shows the Color List window, with six colors listed next to rectangles representing the color.

如果在调试模式下启动 XAML 应用,可利用实时 XAML 编辑。 甚至无需停止应用或按保存按钮。 只需更改 XAML,正在运行的应用中就会立即反映大部分更改。 现在就试试。 将数据模板内 RectangleWidthHeight 更改为 30,从而将颜色矩形变为方形。

Screenshot that shows the Color List window, with six colors listed next to squares representing the color.

这称为 XAML 热重载,它非常适用于微调应用中的布局和动画。

总结

本课介绍了在 ListBox 中显示多个项的基础知识。 具有类似用途的控件还有其他许多,如 ItemsControlListViewGridView。 但基本原则是相同的:将对象列表(IEnumerableList<>)绑定到 ItemsSource 属性,并将 DataTemplate 定义为控制各个列表项的外观和行为方式。 还可以重新定义这些项的布局,甚至是容器控件本身的外观(尽管这超出了本模块范围)。

请注意,逻辑代码从未对 ListBox 控件有任何了解。 它只创建了业务对象集合 (ColorDescriptor),而 XAML 运行时为每个项处理了模板的呈现。

下一课将介绍可以如何从 ListBoxComboBox 中选择项,并更改代码中的列表内容,以便在 UI 中反映元素添加和删除。