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

.NET WPF 4: 探索数据绑定的强大功能

2010 年 5 月 7 日

CPOL

7分钟阅读

viewsIcon

33827

downloadIcon

1110

从 Windows Forms 到 WPF,有一点改变了,那就是我们将控件绑定到数据源并将其显示给用户的方式。

WPFDataBinding_src

引言

从 Windows Forms 到 WPF,有一点改变了,那就是我们显示数据的方式;不仅是视觉方面,真正改变的是我们将控件绑定到数据源并将其显示给用户的方式。

为了稍微说明一下 WPF 数据绑定的新范例,我们将制作一个小型应用程序(之所以小,是因为 XAML 和代码加起来不超过 85 行),它将允许我们在数据网格中显示客户订单,并且通过选择任何订单,我们可以在数据网格旁边的列表框中看到订单中包含的产品,并在下方看到客户的联系信息。

代码

准备数据源

在这种情况下,我使用了 Access 中的 Northwind 数据库,以便更轻松地使用它。我已经将其包含在本页面顶部的示例项目中,但您也可以在此处下载它。

拥有数据库 Nwind.mdb 后,将其复制到您的项目目录中,然后从菜单 Project -> Add Existing Item 中,选择 NWind.mdb 文件,Visual Studio 2010 将打开数据源配置向导。

WPFDataBinding2.PNG

选择 DataSet 并按 Next,向导将提示您选择要包含在数据集中的数据库对象。

WPFDataBinding3.PNG

我选择了所有表,但我们的项目只需要 Customers、Order Details、Orders、Products 和 Shippers。选择表,在数据集名称文本框中为数据集命名,然后按 Finish。数据库将包含在我们的项目中,Visual Studio 将创建一个类型化数据集文件 (.xsd)。如果打开它,您会看到类似这样的内容(取决于您选择的表):

WPFDataBinding4.PNG

这是数据集的视觉表示。每个框有两个部分,顶部是带有字段的表,底部(名称与表名 + TableAdapter 相同)是我们用于从该表中检索记录的对象。您还会看到连接表的线条。这些是它们之间的关系。如果单击它们,它们会变成蓝色;然后删除所有这些,因为我们将在下一步中创建它们。

让我们在表 Orders(父表)和 Order Details(子表)之间创建一个新关系。为此,右键单击 Order Details 的标题,然后在上下文菜单中,选择 Add 并单击 Relation。您将看到一个如下所示的窗口:

WPFDataBinding6.PNG

订单和订单详情关系

属性

名称

OrderDetails

父表

订单

子表

订单详情

键列

OrderID

外键列

OrderID

现在以相同的方式并使用以下参数创建 Order Details 和 Products 表之间的关系:

订单详情和产品关系

属性

名称

产品订单详情

父表

OrderDetails

子表

产品

键列

ProductID

外键列

ProductID

同样,Customers 和 Orders 表之间的关系

订单和客户关系

属性

名称

客户订单

父表

订单

子表

Customers

键列

CustomerID

外键列

CustomerID

最后,Orders 表和 Shippers 表之间的关系

订单和发货人关系

属性

名称

发货人订单

父表

订单

子表

发货人

键列

通过发货

外键列

发货人ID

至此,我们已经完成了数据源的准备。现在我们将设计我们的窗口。

设计我们的窗口

我们将设计我们的窗口。它由一个分成两行两列的网格组成。我们将第一行用作标题,第二行将包含内容。在第二行的第一列中,我们将插入一个显示客户订单的数据网格,在第二列中,我们将插入显示当前选定订单详细信息的控件。

WPFDataBinding7.PNG

网格的 XAML 代码如下:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="75*"></ColumnDefinition>
        <ColumnDefinition Width="25*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
</Grid>

这很简单,只是简单地说明了行和列的定义,以及可变或固定大小。

现在我们将插入 DataGrid 的标题和 DataGrid 本身,并指定它所属的列和行。

<ContentPresenter Grid.Row="0" Grid.Column="0" 
    VerticalAlignment="Center" Content="Data Grid."/>
<DataGrid Name="grdData" Grid.Row="1" Grid.Column="0" 
    Margin="5" VerticalAlignment="Stretch" 
    HorizontalAlignment="Stretch" AutoGenerateColumns="False" 
    IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}">
</DataGrid>

如您所见,在我的例子中,我选择不自动定义列(AutoGenerateColumns = "false")。为了定义要显示的列的绑定,在两个控件中的每一个中,我指定了附加属性 Grid.ColumnGrid.Row 来将控件放置在它所属的位置。在 DataGrid 中,我还将属性 IsSynchronizedWithCurrentItem 设置为 true。此属性非常重要,因为它将使其他控件能够使用当前选定的数据。

DataGrid 中,我们必须指定要显示的列。我们将以下 XAML 代码包含到 DataGrid 中:

<DataGrid.Columns>
    <DataGridTextColumn Header="Order Code" 
       Binding="{Binding Path=OrderID}" MinWidth="80"/>
    <DataGridTextColumn Header="Customer" 
        Binding="{Binding Path=CustomersOrders/CompanyName}" 
        MinWidth="200"/>
    <DataGridTextColumn Header="Order Date" 
        Binding="{Binding Path=OrderDate}" MinWidth="100"/>
    <DataGridTextColumn Header="Shipper" 
        Binding="{Binding Path=ShippersOrders/CompanyName}" 
        MinWidth="200"/>
</DataGrid.Columns>

我们从这里开始受益于 WPF 数据绑定。如您所见,每个列都有一个 Binding 属性。此属性指向您要显示的字段。第一列(订单代码)直接指向 Orders 表中的 OrderID 字段,这将是我们的主要 DataContext。订单日期也一样,但您会看到 Customers 和 Shippers 不同。这是因为,我们使用先前创建的关系,将我们的列指向子表并选择其中的一个字段进行显示。我们不必担心带有联接的特定查询。我们只需使用表之间的关系来显示我们需要的字段。

现在我们创建窗口部分以显示选定订单的详细信息

<ContentPresenter Grid.Row="0" Grid.Column="1" 
        VerticalAlignment="Center" Content="Extra Information"/>

<StackPanel Grid.Row="1" Grid.Column="1" Margin="5">
    <ContentPresenter Content="Order Details:"></ContentPresenter>
    <ListBox Name="lstDetallePedidos" Height="125"
             ItemsSource="{Binding Path=OrderDetails}"
             DisplayMemberPath="ProductsOrderDetails/ProductName"
             IsSynchronizedWithCurrentItem="True" >
    </ListBox>

    <ContentPresenter Content="Customer Code:"></ContentPresenter>
    <TextBox Name="txtCustomerCode" 
          Text="{Binding Path=CustomerID}"></TextBox>
    <ContentPresenter Content="Company:"></ContentPresenter>
    <TextBox Name="txtCompany" 
          Text="{Binding Path=CustomersOrders/CompanyName}"></TextBox>
    <ContentPresenter Content="Contact person:"></ContentPresenter>
    <TextBox Name="txtContact" 
          Text="{Binding Path=CustomersOrders/ContactName}"></TextBox>
    <ContentPresenter Content="Contact phone:"></ContentPresenter>
    <TextBox Name="txtPhone" 
          Text="{Binding Path=CustomersOrders/Phone}"></TextBox>
</StackPanel>

您会发现这本身非常简单。我们在第 1 列第 0 行使用了一个 ContentPresenter 来定义标题,然后,在第 1 行第 1 列中,我们引入了一个 StackPanel,因为我们想要一个简单的元素布局。与 DataGrid 的列一样,在这里我们将每个 TextBox 的 Text 属性绑定到我们想要显示的 Orders 表中的字段,并使用关系显示其他表中的字段。

略有不同的是 ListBox 控件,因为在这里,我们为数据绑定设置了两个属性。在 ItemsSource 中,我们建立了 OrderDetails 关系。这样,我们获得的项数与 Orders 表和 OrderDetails 之间的关系相同(即,如果一个订单包含两个 OrderDetails,我们就会获得这两个项)。但是,要设置 DisplayMemberPath 属性,我们使用第二个关系 ProductsOrderDetails 来绑定到产品表和 ProductName 字段。由于我们不感兴趣显示选定的产品 ID(位于 OrderDetails 表中),我们想要 Products 表中找到的名称。因此,我们使用 ProductsOrderDetails 关系来为列表框的每个项移动到 Products 表。

至此,我们已经完成了窗口的设计和准备。现在我们只需要编写使所有这些工作的代码,我说“只需要”,因为它真的非常简单和容易。

代码编写

好的,首先我们必须打开与我们的 XAML 代码关联的文件,并声明包含我们的数据和用于填充它的 TableAdapter 实例的私有成员。

'Private Objects definition.
Private dsDatos As New NwindDataSet
Private custAdap As New NwindDataSetTableAdapters.CustomersTableAdapter
Private ordeAdap As New NwindDataSetTableAdapters.OrdersTableAdapter
Private detailAdap As New NwindDataSetTableAdapters.Order_DetailsTableAdapter
Private shipAdap As New NwindDataSetTableAdapters.ShippersTableAdapter
Private prodAdap As New NwindDataSetTableAdapters.ProductsTableAdapter

我们定义了我们的数据集 dsDatos 和填充 Customers、Orders、Order_Details、Shippers 和 Products 表所需的 TableAdapter。

现在在窗口的构造函数中,我们将加载数据并设置控件的数据源。

Public Sub New()
    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    ' Fill Tables.
    custAdap.Fill(dsDatos.Customers)
    detailAdap.Fill(dsDatos.Order_Details)
    shipAdap.Fill(dsDatos.Shippers)
    prodAdap.Fill(dsDatos.Products)
    ordeAdap.Fill(dsDatos.Orders)

    ' Stablish Orders Table as our Window DataContext
    Me.DataContext = dsDatos.Orders
End Sub

这段代码并不复杂。在调用 InitializeComponent(由 Visual Studio 在创建窗口的 Sub New 时自动创建)之后,我们只需使用我们的 TableAdapters 来填充我们 DataSet dsDatos 中的表。

我们应用程序中最重要的一行代码是最后一行

Me.DataContext = dsDatos.Orders

此行将窗口的数据上下文设置为 Orders 表,该表将获取所有关系和所需的字段。WPF 数据绑定的魔力就发生在这里。在 XAML 代码中,每个控件都在其父控件中搜索其数据源,并在窗口中获取它。这样,所有未指定数据源的控件都共享相同的源,并且通过使用 IsSynchronizedWithCurrentItem 属性,如果您更改 Orders 表中选定的项,所有控件都会自动反映更改。

而且……没有更多的代码了。这就是使窗口完美运行所需的所有代码。您只需运行应用程序即可查看结果。

历史

  • 2010 年 5 月 7 日 - 初次发布。
© . All rights reserved.