Windows Presentation Foundation 数据绑定:第一部分

来源:百度文库 编辑:神马文学网 时间:2024/04/29 04:52:06
show toc
欢迎来到 MSDN >Windows 开发
Windows Presentation Foundation 数据绑定:第一部分
发布日期: 2006-6-5 | 更新日期: 2006-6-5
适用于:
Microsoft Windows Presentation Foundation
摘要:本文阐释如何使用基于 XAML 的数据绑定在 Microsoft Windows Presentation Foundation 项目中执行数据操作。

本页内容
简介
简化的 XAML 绑定
我们所处的位置
参考资料
简介
Windows Presentation Foundation(以前称作 Avalon)为胖客户端开发用户界面引入了一个意义深远的新方法。WPF 第一次将用户界面设计与代码设计相分离。这种分离意味着,通常标记在一个文件中而代码则在另一个文件中,这与 ASP.NET 很类似。然而,这种分离仅在编译时存在。标记文件用于生成形成代码文件的代码,进而生成应用程序。
为了便于设计,Microsoft 开发了一种丰富的标记语言,称作 XAML。XAML 是一种基于 XML 的标记语言,它支持一个用于开发特定应用程序的新模型,这些应用程序具有对许多不同的用户界面概念的本机支持,如 2D 和 3D 绘图、动画、控件包容、控件和文档流,以及一个丰富的数据绑定模型。本文将概述 WPF 数据绑定,并假定您对 WPF 有一定的了解。如果您还不了解 WPF,请参阅 Tim Sneath 的Architectural Overview of the Windows Presentation Foundation Beta 1 Release 一文进行概览。
为什么使用数据绑定?
如果您要开始使用 WPF,可能想知道:不用学习数据绑定,只编写代码来执行项目中的大部分数据操作是否更容易。虽然这可能是一个有效的方法,但我猜想您将逐渐使用基于 XAML 的数据绑定,甚至可能会爱上它。下面我们来看一个小示例。
图 1 显示一个简单 WPF 项目的用户界面。它是 RSS 提要的编辑器,允许用户查看和编辑提要。

图 1. 我们的 RSS 编辑器
该编辑器的布局相当简单,如以下 XAML 代码所示。
BlogEditor Title: Url: Date: Body:
请注意加粗显示的事件处理程序。那里是大部分代码将发生的地方,加载 RSS 提要并填充 WPF 控件。
C#:
XMLDocument blog = new XMLDocument(); const string BLOGURL = @"z:\adoguy.RSS"; public Window1() { InitializeComponent(); blog.Load(BLOGURL); } void Window1_Loaded(object sender, RoutedEventArgs e) { FillListBox(); } void FillListBox() { entryListBox.Items.Clear(); XMLNodeList nodes = blog.SelectNodes("//item"); foreach (XMLNode node in nodes) { ListBoxItem item = new ListBoxItem(); item.Tag = node; item.Content = node["title"].InnerText; entryListBox.Items.Add(item); } }
Visual Basic .NET:
Dim blog As New XMLDocument Const BLOGURL As String = "z:\adoguy.RSS" Public Sub New() InitializeComponent() blog.Load(BLOGURL) End Sub Sub Window1_Loaded(ByVal sender As Object, _ ByVal e As RoutedEventArgs) FillListBox() End Sub Sub FillListBox() entryListBox.Items.Clear() Dim nodes As XMLNodeList = blog.SelectNodes("//item") For Each node As XMLNode In nodes Dim item As New ListBoxItem item.Tag = node item.Content = node("title").InnerText entryListBox.Items.Add(item) Next End Sub
在这段代码中,您可以看到:我们用 RSS 提要加载一个 XML 文档,用所有项的标题填充 ListBox。
接下来,我们需要处理在 ListBox 中进行选择时将发生的事情。
C#:
void entryListBox_Changed(object sender, RoutedEventArgs e) { if (entryListBox.SelectedIndex != -1) { XMLNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XMLNode; if (node != null) { titleText.Text = node["title"].InnerText; URLText.Text = node["guid"].InnerText; dateText.Text = node["pubDate"].InnerText; bodyText.Text = node["description"].InnerText; } } }
Visual Basic .NET:
Sub entryListBox_Changed(ByVal sender As Object, _ ByVal e As SelectionChangedEventArgs) If entryListBox.SelectedIndex <> -1 Then Dim node As XMLNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag If Not node Is Nothing Then titleText.Text = node("title").InnerText URLText.Text = node("guid").InnerText dateText.Text = node("pubDate").InnerText bodyText.Text = node("description").InnerText End If End If End Sub
当 ListBox 更改时,我们用所选的 RSS 提要项填充 TextBoxes。可以通过获取提要项的内部文本来执行该操作。请注意,我们还需要用 ListBoxItem, 保留节点的一份副本,进行一些转换以到达每个事件处理程序。
最后,我们需要处理单击 Update 按钮时发生的事情。
C#:
void updateButton_Click(object sender, RoutedEventArgs e) { if (entryListBox.SelectedIndex != -1) { XMLNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XMLNode; if (node != null) { node["title"].InnerText = titleText.Text; node["guid"].InnerText = URLText.Text; node["pubDate"].InnerText = dateText.Text; node["description"].InnerText = bodyText.Text; blog.Save(BLOGURL); FillListBox(); } } }
Visual Basic .NET:
Sub updateButton_Click(ByVal sender As Object, _ ByVal e As RoutedEventArgs) If entryListBox.SelectedIndex <> -1 Then Dim node As XMLNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag If Not node Is Nothing Then node("title").InnerText = titleText.Text node("guid").InnerText = URLText.Text node("pubDate").InnerText = dateText.Text node("description").InnerText = bodyText.Text blog.Save(BLOGURL) FillListBox() End If End If End Sub
在此处,假如更改了标题,我们用新信息更新节点,保存 XML 文档,并导致重新填充 ListBox。尽管这只是一个简单的小应用程序,但需要的代码还是有点儿多。使用 XAML 数据绑定执行该操作是否会简单些?是的,会更简单。以下是同一个项目的 XAML,使用 XAML 数据绑定。
Blog Editor ItemsSource="{Binding Source={StaticResource RSSFeed}, XPath=//item}" > Text="{Binding XPath=title}" /> DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" > Title: Text="{Binding XPath=title}" /> URL: Text="{Binding XPath=guid}" /> Date: Text="{Binding XPath=pubDate}" /> Body: Text="{Binding XPath=description}" />
这段 XAML 代码运行时没有任何隐藏的代码。图 2 显示只使用 XAML 的应用程序(使用 XAMLPad)。

图 2. XAMLPad 中的 RSS 编辑器
您可能想知道"它是如何运行的"?它之所以运行,是因为我们使用 XAML 绑定来为我们做大量的工作。虽然以后会详细介绍 XAML 中涉及的每项技术,但我们还是先浏览一下数据绑定的各部分内容,从而解释它在实际工作中的情况。
首先,创建一个 XMLDataProvider 对象来加载和管理编辑器的 XML 文档。

它告诉 XAML 从 Z: 驱动器加载一个 XML 文档,以填充窗体。
接下来,绑定 ListBox。

这段代码告诉列表框查找名为 RSSFeed 的 XAML 中的资源,然后将其用作数据源。此外,它还告诉列表框从 XPath 表达式获得要绑定到的项的列表(在本例中是文档中的所有项元素)。
接下来,通过指定数据模板来指定要在列表框的各项中显示的内容。

这段代码告诉 ListBox 为每项创建一个 TextBlock 对象,并使用 XPath 确定要在 TextBlock 中显示的内容。
接下来,绑定包含所有详细信息的网格。

在此处,我们告诉 XAML 将容器(在本例中是 Grid)绑定到 ListBox 的选定项。我们使用 ElementName 而不是 Source,因为我们希望绑定到 XAML 文档中的某个控件,而不是一些外部数据。通过设置 DataContext,允许将 Grid 中的所有控件设置为同一个对象(在本例中是 SelectedItem)。
接下来,我们将每个 TextBox 绑定到所需的 XML 文档部分。
Title: Url: Date: Body:
由于我们设置了 DataContext,因此可以仅指定 XPath 表达式,以获得我们需要的 RSS 提要的部分。
一下尝试接受这些内容太多了。停下来喘口气。我并不指望你们一下子都能接受。在下面部分中,我将前面示例的许多观点分成各个更易于管理的部分。
返回页首
简化的 XAML 绑定
要从一个有关 Binding 对象如何工作的简单示例开始,我们先从下面这个非常简单的 XAML 文档入手。
Test
这段代码创建了一个简单的画布,包含两个控件,如图 3 所示。

图 3. 简单的 XAML 画布
我们可能希望绑定 TextBlock,以便按照键入的方式显示 TextBox 的文本。为此,我们需要一个 Binding 对象将两个对象绑定在一起。首先要向 TextBox 添加一个名称,这样我们才能通过元素名引用元素。

接下来,我们需要向 TextBlock 的 Text 元素添加一个 Binding。

这段代码告诉 TextBlock 的 Text 要设置为 TextBox 控件中的用户类型。
将以上这几段代码组合在一起即可产生以下代码。

这段 XAML 代码创建了一个窗体,该窗体按照在 TextBox 中键入的内容更改 TextBlock,如图 4 所示。

图 4. 绑定控件
祝贺您!您已经拥有了自己的第一个绑定!但是这个 XML 语法有点冗长。应该有更好的编写方法。
使用绑定简化版本
在上一示例中我们了解到,如何将 Binding 元素添加到属性来创建数据绑定。在这个简单的示例中,以这种方式进行数据绑定似乎不太麻烦;然而,随着 XAML 文档的增大,这个冗长的语法可能会变得比较麻烦。为了缓解这个问题,XAML 支持绑定语法的一个简化版本。
例如,使用简化版本,上一示例如下所示。

简化语法包含在大括号 ({}) 中,以单词 Binding 开始,包含绑定属性的名称/值对。简化语法的目的是使数据绑定需要更少的击键,并且更易于阅读。本文的剩余部分,我将使用简化语法。
绑定源
目前为止,我们已经将另一个控件用作所有绑定示例的源。然而,在大多数基于 XAML 的项目中,您将绑定到除其他控件外的源。大多数数据绑定的关键是 Source 属性。在前面的示例中,我们使用的是 ElementName 属性(它用于绑定到一个控件),而不是使用 Source 属性。对于大多数应用程序,您希望绑定到更重要的源,如 XML 或 .NET 对象。XAML 用其 provider 对象支持该操作。XAML 中内置有两种类型的数据提供程序:ObjectDataProvider 和 XMLDataProvider。ObjectDataProvider 用于绑定到 .NET 对象以及从 .NET 对象绑定,并不奇怪的是,XMLDataProvider 用于绑定到 XML 片段和文档以及从 XML 片段和文档进行绑定。您可以在任何 XAML 容器的资源部分中指定一个数据提供程序。
使用 XMLDataProvider
例如:
Blue Black Green Red XML Example
在 StackPanel 的资源中,我们有一个 XMLDataProvider 对象。x:Key 表示 Binding 对象中用来引用它的名称。在该提供程序中,我们创建了 XML 内联,用作数据绑定的源。在 ListBox 的 Binding 中,我们将提供程序指定为绑定的 Source。如果某个数据源位于 XAML 文档中,您需要指定该对象是一个静态源,如此处所示。最后,我们使用 XPath 语句指定应该使用 XML 文档中的哪个集合来填充 ListBox。该代码生成图 5 所示的窗体。

图 5. XML 数据绑定
或者,我们可以指定:该提供程序应该使用路径或 URL 来查找用来创建相同窗体的 XML 的源,方法是指定 XMLDataProvider 的 Source 属性。

XMLDataProvider 的 Source 属性也可以指向标准 URL,从而使您能够创建到 XML API(如 RSS)的快速访问。
XML Example
通过调出到一个 RSS 提要,可以创建一个页面,它在 ListBox 中快速列出我的网络日记中的所有主题,如图 6 所示。

图 6. 我的网络日记的主题列表
使用 ObjectDataProvider
有时需要到 .NET 对象的绑定。这就是引入 ObjectDataProvider 的地方。该数据提供程序使您能够为 .NET 数据类型创建绑定。
例如,我们可以在 .NET 中创建一个简单的字符串集合,如下所示。
public class MyStrings : List { public MyStrings() { this.Add("Hello"); this.Add("Goodbye"); this.Add("Heya"); this.Add("Cya"); } }
- 或者 -
Public Class MyStrings Inherits List(Of String) Public Sub New() Me.Add("Hello") Me.Add("Goodbye") Me.Add("Heya") Me.Add("Cya") End Sub End Class
也可以在 XAML 文档中使用一条处理指令将 CLR 对象的整个命名空间添加到该文档所支持的类型中,方法是将该命名空间指定为一个 xmlns 声明。例如,我们可以将整个命名空间的类映射到 XAML 中,如下所示。

要从外部程序集导入类,可以指定一个 xmlns 声明,仅指定程序集名称,如下所示。

一旦已经导入了类型,就可以使用 ObjectDataProvider 指定来自其中一种类型的数据源。
Simple Source Example
也可以通过要使用的命名空间和类型指定一个 XAML 元素,来创建资源,如下所示。
Simple Source Example
该语法的工作方式就像 ObjectDataSource 一样,只不过更易于使用。既然已经导入了命名空间,我们就可以添加一个引用我们的数据源类的资源了,方法是指定该类的名称(例如, MyStrings)。数据绑定与前面的示例相同,因为 XAML 代码并不关心它是何种数据源,只要是数据源就可以了。
绑定模式
在大多数情况下,您希望绑定是一个双向绑定。Binding 对象支持几种模式以支持不同的用例,如表 1 所示。
表 1. 绑定模式
绑定模式 说明
TwoWay
双向移动绑定控件或绑定源的改动。(这是默认模式。)
OneWay
仅将改动从源移动到控件。当源发生改动时,绑定控件的数据也相应更改。
OneTime
数据仅在启动时绑定,第一次用数据填充控件后忽略对源的更改。
只需在标记中包括模式即可指定模式,如下所示。
{Binding ElementName=theTextBox, Path=Text, Mode=OneTime}
一种了解双向绑定工作方式的方法是创建一个具有两个文本框的Canvas,一个文本框绑定到另一个文本框。

如果将这段代码粘贴到 SDK 附带的 XAMLPad 工具中,您应该注意到,源文本框按照您键入的内容更新绑定的文本框,但是,从绑定控件到源控件的更新仅发生在绑定控件失去焦点时。如果将 Mode 更改为 OneWay 或 OneTime,就会看到这些不同的模式是如何更改绑定的工作方式的。
控制绑定时间
除了模式,您还可以使用UpdateSourceTrigger 指定绑定何时推出更改。您可以指定绑定仅在指定的时间进行更改,方法是指定 UpdateSourceTrigger 类型。
{Binding ElementName=theTextBox, Path=Text, UpdateSourceTrigger=LostFocus}
UpdateSourceTrigger 属性指定何时用改动更新源。这仅对 Mode=TwoWay 绑定(默认方式)有效。表 2 显示 UpdateSourceTrigger 的有效值。
表 2. UpdateSourceTrigger 值
UpdateSourceTrigger 说明
Explicit
源仅通过显式调用 BindingExpression.UpdateSource 方法更新。
LostFocus
绑定控件失去焦点时更新源。
PropertyChanged
每次属性更改时都将改动更新到源。这是默认行为。
使用 DataContext
本文要介绍的最后一个概念是如何使用DataContext。DataContext 专门用于指定某个容器中的所有控件都将绑定到一个公共对象。
例如,以下是一个示例:我们有一个 Canvas,它将显示 XML 文档中特定节点的值和文本。
Blue Black Green Red XML DataContext Example
通过将DataContext 设置为 XML 文档(以及一个特定的 XPath 表达式),我们告诉 Canvas:其中所有不包含 Source 的控件都可以使用容器的 DataContext。这样,只需指定 XPath 表达式就能绑定 TextBlock。请注意,每个 TextBlock 中的 XPath 表达式都是相对的 XPath 表达式。这对于对象绑定也一样。
Object DataContext Example
使用对象代替 XML 仅仅意味着您将使用 Path 表达式代替 XPath 表达式。
返回页首
我们所处的位置
我们已经了解了在 XAML 中如何用 Binding 对象直接进行数据绑定,既有简化版本又有普通版本。通过利用 XML 或对象数据提供程序,我们可以绑定到应用程序中不同类型的对象。我们还看到如何使用 Binding 对象的 ElementName 语法绑定到其他控件。在本系列的下一部分中,我将向您介绍如何利用该信息并将其绑定到实际的数据库数据,使用您自己的对象或 .NET 数据容器(例如,DataSources 和 DataSets)。
返回页首
参考资料

Windows SDK (includes WinFX)

Programming the Windows Presentation Foundation,Chris Sells 和 Ian Griffiths
转到原英文页面
返回页首

 适合打印机打印的版本 通过电子邮件发送此页面
个人信息中心 |MSDN中文速递邮件 |联系我们
©2007 Microsoft Corporation. 版权所有.  保留所有权利 |商标 |隐私权声明