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

WPF 数据绑定的基本示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.22/5 (6投票s)

2015年1月4日

CPOL

5分钟阅读

viewsIcon

18973

downloadIcon

378

如何在 WPF 中执行简单的控件数据绑定。涵盖单向和双向绑定。

引言

本文旨在介绍 WPF 数据绑定的概念,通过示例展示如何使用自定义 `List(Of)` 填充 `DataGrid`,并通过 `TextBox` 和 `DatePicker` 等控件进行修改,这些控件的数据源将来自 Grid 本身。众所周知,Windows Presentation Foundation 引入的主要功能之一是能够轻松地将用户控件(和对象)与不同复杂性的数据源连接起来,并将它们的表示任务留给框架(尽管您始终可以稍后对其进行自定义)。作为一种可能的用法场景示例,我们假设有一个 Grid 公开来自给定自定义结构的数据,并在稍后通过简单的文本控件实现其变化。

示例类

假设我们有一个假想的类 `Articolo`,它允许我们定义要存储的产品,并包含产品代码(`Codice`)、描述(`Descrizione`)和有效期(`DataScadenza`)。我们将这个类(虽然简化,但对我们来说很有用)声明如下:

Public Class Articolo
        Dim _codice As String
        Dim _descrizione As String
        Dim _datascadenza As Date
 
        Public ReadOnly Property Codice As String
            Get
                Return _codice
            End Get
        End Property
 
        Public Property Descrizione As String
            Get
                Return _descrizione
            End Get
            Set(value As String)
                _descrizione = value
            End Set
        End Property
 
        Public Property DataScadenza As Date
            Get
                Return _datascadenza
            End Get
            Set(value As Date)
                _datascadenza = value
            End Set
        End Property
 
        Public Sub New(codart As String, desart As String)
            _codice = codart
            _descrizione = desart
            _datascadenza = New Date(Now.Year + 1, Now.Month, Now.Day)
        End Sub
End Class

在类构造函数中,只要求提供代码和描述参数。有效期设置为一年后。定义类的属性是可编辑的,唯一例外是 `Codice`(产品代码),它在创建后无法更改。

接下来,我们将用一些示例数据填充产品列表,这些数据将用于后续步骤。假设我们有一个名为 _MainWindow.xaml_ 的 WPF 窗口。我们将创建一个 `Loaded` 事件的事件管理器,XAML 如下所示:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ERP_test" x:Class="MainWindow"
    Title="MainWindow" Height="269" 
    Width="563" Loaded="Window_Loaded">
</Window>

事件后面的代码将是:

Dim prodotti As List(Of Articolo)

Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    prodotti = New List(Of Articolo)
    prodotti.Add(New Articolo("Prodotto01", "ARTICOLO TEST"))
    prodotti.Add(New Articolo("Prodotto02", "PROVA"))
    prodotti.Add(New Articolo("Prodotto03", "NESSUNA DESCRIZIONE"))
End Sub

很简单,我们将有一个全局的 `List(Of Articolo)` 列表,名为 `prodotti`,它在首次执行时包含三个产品。这种结构代表了我们将通过绑定在 `DataGrid` 中公开的数据源。让我们看看如何实现。

DataGrid 上的数据绑定

在我们的窗口中,我们将添加一个名为 `DataGrid1` 的 `DataGrid` 控件。由于我们的结构是在代码中定义的,因此我们必须在此处工作以将控件链接到其数据源。绑定将通过控件的 `ItemsSource` 属性获得。我们的 `Loaded` 事件将修改如下:

Dim prodotti As List(Of Articolo)
 
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    prodotti = New List(Of Articolo)
 
    prodotti.Add(New Articolo("Prodotto01", "ARTICOLO TEST"))
    prodotti.Add(New Articolo("Prodotto02", "PROVA"))
    prodotti.Add(New Articolo("Prodotto03", "NESSUNA DESCRIZIONE"))
 
    DataGrid1.ItemsSource = prodotti
End Sub

`ItemsSource` 确实是通过该属性(类型为 `System.Collections.IEnumerable`)来设置(或读取)数据集合,后者用于控件的内容生成(在我们的例子中是 Grid)。`DataGrid` 的绑定已完成:从我们程序第一次执行开始,我们将看到类似以下的输出:

控件之间的数据绑定:Datagrid 到 TextBox 和 DatePicker

正如之前描述的,我们不仅仅需要一个产品列表。我们希望能够通过滚动列表来查看产品详细信息。在实现这种实现时,我们将使用一些 `TextBox` 控件,并在它们(作为接收者)和 `DataGrid`(作为源)之间执行绑定,允许接收控件(`TextBox` 或 `DatePicker`,对于有效期)修改它们的源。让我们将我们的窗口修改如下:

`TextBox` 和 `DatePicker` 中公开控件值的属性分别是 `Text` 和 `SelectedDate`。因此,有必要在这些属性上设置数据绑定。本质上,在识别将接收特定数据的属性后,我们必须指示其源以及其他信息(其中一些是可选的),这些信息将决定这些数据如何交换。在我们的例子中,希望通过接收控件的变化来修改 `DataGrid` 的内容,我们必须使用某种双向方法。

作为要在控件之间执行的操作,可以直接干预 XAML 代码,指示 `TextBox` 和 `DatePicker` 如何链接到 `DataGrid`。与这三个控件相关的代码将修改如下:

<TextBox HorizontalAlignment="Left" Height="23" Margin="445,42,0,0"
         TextWrapping="Wrap" VerticalAlignment="Top" Width="181"
         Text="{Binding SelectedItem.Codice,ElementName=DataGrid1 , Mode=OneWay }"/>
 
<TextBox HorizontalAlignment="Left" Height="23" Margin="445,70,0,0"
         TextWrapping="Wrap" VerticalAlignment="Top" Width="181"
         Text="{Binding SelectedItem.Descrizione,ElementName=DataGrid1 , Mode=TwoWay }"/>
 
<DatePicker HorizontalAlignment="Left" Margin="445,98,0,0"
            VerticalAlignment="Top" Width="181"
            SelectedDate="{Binding SelectedItem.DataScadenza,ElementName=DataGrid1 ,Mode=TwoWay }"/>

如前所述,公开特定数据的属性必须设置为指示数据源以及检索数据的方式。我们以 #1(公开产品代码 `Codice` 的 `TextBox`)为例:

在这种情况下,我们将看到源控件设置在 `DataGrid1` 上,我们从中读取当前 `SelectedItem` 属于 `Articolo` 类的 `Codice` 属性。绑定的模式是单向的,即从源(`DataGrid1`)到目标(`TextBox`),反之亦然:事实上,我们将 `Codice` 属性定义为只读(参见片段 1),任何尝试更改其值的行为都将引发异常。

类似地,在另外两种情况下,我们将始终以 `DataGrid1` 作为源控件,引用的属性将是 `Descrizione`(描述)和 `DataScadenza`(有效期),但绑定模式将是 `TwoWay`,即双向:修改控件的内容将导致更新其源属性/控件,或 `DataGrid1`(以及扩展到与之关联的列表)。

运行我们的程序,尝试定位到第二个记录(例如)并修改数据,我们可以验证链接控件数据的正确更新:

DataGrid 填充的替代方法

我们在这里看到了一种填充 `DataGrid` 的方法,该方法涉及 `List(Of <Our_Class>)`。说到 WPF 绑定的灵活性,还有其他方法可以填充控件的内容。例如,我们的 `Articolo` 类可以直接在 Grid 的 XAML 中引用。如果我们想让我们的 `DataGrid` 预先加载一些记录,我们可以这样做:

<DataGrid Name="DG1" HorizontalAlignment="Left" 
Height="153" Margin="10,10,0,0" 
    VerticalAlignment="Top" Width="305" 
    xmlns:local="clr-namespace:WinTest"  >
            <DataGrid.Columns >
                <DataGridTextColumn Header="Codice" 
                Binding="{Binding Codice}"/>
                <DataGridTextColumn Header="Descrizione" 
                Binding="{Binding Descrizione}"/>
                <DataGridTextColumn Header="Data di scadenza" 
                Binding="{Binding DataScadenza}"/>
            </DataGrid.Columns>
            <local:Articolo Codice="CODE_01" 
            Descrizione="MSDN TEST" DataScadenza="2014-12-01" />
</DataGrid>

我们使用 `xmlns:local` 关键字来指定我们的类作为引用(在我的例子中是 `WinTest`)。这样,我们就可以在 XAML 中使用我们命名空间内的每个类(在我的例子中是 `Articolo`)。然后我们定义三个 `DataGridColumns`,每个都与我们类的特定属性绑定。然后,使用 `local` 标签,我们可以定义可变数量的记录,设置每个记录的参数。上面的代码将生成以下窗口:

从这种情况开始,我们可以通过代码添加其他行,使用 `DataGrid` 公开的 `Item` 集合。假设我们的 `DataGrid` 名为 `DataGrid1`,我们可以例如在 `Loaded` 事件中使用以下代码向其中添加第二行:

DataGrid1.Items.Add( New Articolo("CODE_02", "MSDN TEST 2") )

请注意:只要存在动态或静态生成的行(即 `Item` 集合不为空),就无法使用上面讨论的 `ItemsSource` 属性。为了将结构绑定到我们的 `DataGrid`,我们必须首先清空 `Item` 集合(例如,使用类似:`DataGrid1.Items.Clear()` 的代码),然后我们才能成功设置 `ItemsSource` 属性。

历史

  • 2015-01-05:已添加源代码
  • 2015-01-04:CodeProject 初版发布
© . All rights reserved.