Windows Presentation Foundation数据绑定:第 1 部分
Shawn Wildermuth
2006 年 5 月
适用于:
Microsoft Windows Presentation Foundation
总结:说明如何使用基于 XAML 的数据绑定在 Microsoft Windows Presentation Foundation 项目中执行数据操作。 (16 个打印页)
目录
简介
XAML 绑定,简化
我们在哪?
参考
简介
Microsoft Windows Presentation Foundation (WPF;以前为 Avalon) 引入了一种为丰富客户端开发用户界面的深刻新方法。 WPF 首次将用户界面的设计与代码分开。 这种分离意味着,与 ASP.NET 非常类似,标记通常位于一个文件中,而代码位于另一个文件中。 不过,这种分离仅在编译时存在。 标记文件用于生成与代码文件结婚的代码,以便生成应用程序。
为了便于设计,Microsoft 开发了一种称为 XAML 的丰富标记语言。 XAML 是一种基于 XML 的标记语言,它支持用于开发对多种不同用户界面概念(如二维和三维绘图、动画、控件包含、控件和文档流以及丰富的数据绑定模型)具有本机支持的应用程序的新模型。 本文将概述 WPF 数据绑定。 本文假设你对 WPF 有一些粗略的了解。 如果不这样做,请参阅 Time Sneath's Hitchhiker 的 WPF Beta 1 指南 一文以获取概述。
为何使用数据绑定?
如果你开始使用 WPF,你可能想知道是否更容易避免学习数据绑定,而只是编写代码来执行项目中的大部分数据操作。 虽然这可能是一种有效的方法,但我怀疑你会逐渐使用,甚至喜欢基于 XAML 的数据绑定。 让我们以一个小示例为例。
图 1 显示了简单 WPF 项目的用户界面。 它是 RSS 源的编辑器,允许用户查看和编辑源。
图 1. RSS 编辑器 (单击图像以获取更大的图片)
编辑器的布局非常简单,如下面的 XAML 代码所示。
<Window x:Class="ExampleCS.Window1"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="ExampleCS"
Loaded="Window1_Loaded"
>
<StackPanel>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
BlogEditor
</TextBlock>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<ListBox Name="entryListBox"
Height="300"
SelectionChanged="entryListBox_Changed"/>
<Grid Width="500" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1" Name="titleText" />
<TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" Name="urlText" />
<TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" Name="dateText" />
<TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
<TextBox Grid.Row="3" Grid.Column="1"
Name="bodyText"
TextWrapping="Wrap" />
<Button Grid.Row="4"
Grid.ColumnSpan="2"
Grid.Column="1"
Click="updateButton_Click">
Update
</Button>
</Grid>
</StackPanel>
</StackPanel>
</Window>
记下粗体事件处理程序。 这就是大多数代码将发生的位置,即加载 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 源项填充 TextBox 。 我们通过获取源项的内部文本来执行此操作。 请注意,它还要求在 ListBoxItem 周围保留节点的副本,并执行一些强制转换来获取每个事件处理程序。
最后,我们需要处理单击“ 更新 ”按钮时发生的情况。
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。
<StackPanel
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel.Resources>
<XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />
</StackPanel.Resources>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
Blog Editor
</TextBlock>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<ListBox Name="entryListBox"
Height="300"
ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=title}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Width="500"
Margin="5"
DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1"
Name="titleText"
Text="{Binding XPath=title}" />
<TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1"
Name="urlText"
Text="{Binding XPath=guid}" />
<TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1"
Name="dateText"
Text="{Binding XPath=pubDate}" />
<TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
<TextBox Grid.Row="3" Grid.Column="1"
Name="bodyText"
TextWrapping="Wrap"
Text="{Binding XPath=description}" />
<Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1" >
Update
</Button>
</Grid>
</StackPanel>
</StackPanel>
此 XAML 无需任何代码隐藏即可工作。 图 2 显示了仅使用 XAMLPad) 的 XAML (的应用程序。
图 2. XAMLPad 中的 RSS 编辑器 (单击图像以获取较大的图片)
你可能想知道,“这怎么能起作用?”它之所以有效,是因为我们使用 XAML 绑定为我们完成大部分工作。 尽管稍后会详细介绍 XAML 中的每一种方法,但让我们通过数据绑定的各个部分来解释其工作原理。
首先,我们创建一个 XmlDataProvider 对象,用于加载和管理编辑器的 XML 文档。
<XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />
这会告知 XAML 从我的 Z: 驱动器加载 XML 文档,以便填写表单。
接下来,绑定 ListBox。
<ListBox Name="entryListBox"
Height="300"
ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
>
这会告知列表框在 XAML 中查找名为 RssFeed 的资源,并将其用作数据源。 此外,它告知列表框从 XPath 表达式 (获取要绑定到的项列表,在这种情况下,文档中的所有项元素) 。
接下来,通过指定数据模板来指定要在列表框的项中显示的内容。
<DataTemplate>
<TextBlock Text="{Binding XPath=title}" />
</DataTemplate>
这会告知 ListBox 为每个项目创建一个 TextBlock 对象,并使用 XPath 确定要显示在 TextBlock 中的内容。
接下来,绑定包含所有详细信息的网格。
<Grid Width="500"
Margin="5"
DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >
在这里,我们告诉 XAML 将容器 (在本例中 ,网格) 绑定到 ListBox 的选定项。 我们使用 ElementName 而不是 Source,因为我们想要绑定到 XAML 文档中的控件,而不是某些外部数据。 通过设置 DataContext,我们允许 将 Grid 中的所有控件设置为同一对象 (在本例中为 SelectedItem) 。
接下来,我们将每个 TextBox 绑定到所需的 XML 文档部分。
<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1"
Name="titleText"
Text="{Binding XPath=title}" />
<TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1"
Name="urlText"
Text="{Binding XPath=guid}" />
<TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1"
Name="dateText"
Text="{Binding XPath=pubDate}" />
<TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
<TextBox Grid.Row="3" Grid.Column="1"
Name="bodyText"
TextWrapping="Wrap"
Text="{Binding XPath=description}" />
由于我们已经设置了 DataContext,因此只需指定 XPath 表达式即可访问所需的 RSS 源部分。
这是相当多的尝试吞咽在一个口。 停下来喘口气。 我没想到你一下子就拿到了。 在下一部分中,我已将你在上一示例中看到的许多想法分解为更易于管理的内容。
XAML 绑定,简化
若要从 Binding 对象工作原理的简单示例开始,让我们看一下以下非常简单的 XAML 文档。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<Canvas>
<TextBox Text="This is a TextBox" />
<TextBlock Canvas.Top="25" >Test</TextBlock>
</Canvas>
</Window>
这将创建一个包含两个控件的简单画布,如图 3 所示。
图 3. 简单的 XAML 画布
我们可能需要绑定 TextBlock 以在键入 时显示 TextBox 的文本。 为此,我们需要一个 Binding 对象来将两个对象绑定在一起。 首先要做的是向 TextBox 添加一个名称,以便我们可以按元素的名称来引用它。
<TextBox Name="theTextBox" />
接下来,我们需要将 Binding 添加到 TextBlock 的 Text 元素。
<TextBlock Canvas.Top="25">
<TextBlock.Text> <Binding ElementName="theTextBox" Path="Text" /> </TextBlock.Text>
</TextBlock>
这会告知 TextBlock 的 Text 设置为当用户在 TextBox 控件中键入时。
将所有内容组合在一起会生成以下代码。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<Canvas>
<TextBox Name="theTextBox" Text="Hello" />
<TextBlock Canvas.Top="25">
<TextBlock.Text>
<Binding ElementName="theTextBox" Path="Text" />
</TextBlock.Text>
</TextBlock>
</Canvas>
</Window>
此 XAML 创建一个窗体,该窗体会在你在 TextBox 中键入时更改 TextBlock,如图 4 所示。
图 4。 绑定控件
恭喜:你拥有了第一个绑定! 但 XML 语法有点冗长。 应该有更好的方法来编写它。
使用绑定速记
在前面的示例中,我们了解了如何通过将 Binding 元素添加到属性来创建数据 绑定 。 在这个简单的示例中,以这种方式进行数据绑定似乎并不太繁重;但是,随着 XAML 文档的增长,此详细语法可能会变得繁琐。 为了缓解此问题,XAML 支持绑定语法的简写版本。
例如,使用简写,前面的示例如下所示。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<Canvas>
<TextBox Name="theTextBox" Text="Hello" />
<TextBlock Canvas.Top="25"
Text="{Binding ElementName=theTextBox, Path=Text}" />
</Canvas>
</Window>
简写语法括在) ({} 大括号中,以单词 Binding 开头,并包含绑定属性的名称/值对。 简写语法的目的是通过更少的击键和更高的可读性启用数据绑定。 对于本文的其余部分,我将使用速记语法。
绑定源
至此,我们已使用另一个控件作为所有绑定示例的源。 但是,在大多数基于 XAML 的项目中,你将绑定到其他控件以外的源。 大多数数据绑定的关键是 Source 属性。 在前面的示例中,我们使用 ElementName 属性,该属性用于绑定到控件,而不是使用 Source 属性。 对于大多数应用程序,需要绑定到更重要的源,例如 XML 或 .NET 对象。 XAML 使用其数据 提供程序 对象支持此功能。 XAML 中内置了两种类型的数据提供程序: ObjectDataProvider 和 XmlDataProvider。 ObjectDataProvider 用于绑定到 .NET 对象以及从 .NET 对象绑定,毫不奇怪,XmlDataProvider 用于绑定到 XML 片段和文档以及从中绑定 XML 片段和文档。 可以在任何 XAML 容器的 resources 节中指定数据提供程序。
使用 XmlDataProvider
下面是使用 XmlDataProvider 对象的示例。
<StackPanel
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel.Resources>
<XmlDataProvider x:Key="FavoriteColors"> <x:XData> <Colors > <Color>Blue</Color> <Color>Black</Color> <Color>Green</Color> <Color>Red</Color> </Colors> </x:XData> </XmlDataProvider>
</StackPanel.Resources>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
XML Example
</TextBlock>
<ListBox Width="200" Height="300"
ItemsSource="{Binding Source={StaticResource FavoriteColors}, XPath=/Colors/Color}">
</ListBox>
</StackPanel>
在 StackPanel 的资源中,我们有一个 XmlDataProvider 对象。 x:Key 表示在 Binding 对象中引用它时要使用的名称。 在提供程序中,我们创建了内联 XML,以用作数据绑定的源。 若要使用内联数据,必须使用 XData 元素将其括起来,如代码中所示。 在 ListBox 的 Binding 中,我们已将提供程序指定为绑定的源。 当数据源位于 XAML 文档中时,需要指定对象是静态资源,如代码中所示。 最后,我们使用 XPath 语句指定应使用 XML 文档中的哪个集合来填充 ListBox。 此代码生成如图 5 所示的窗体。
图 5。 XML 数据绑定
或者,通过指定 XmlDataProvider 的 Source 属性,我们可以指定提供程序使用路径或 URL 查找 XML 的源,以创建同一窗体。
<XmlDataProvider x:Key="FavoriteColors"
Source="D:\Writing\msdn\avalondatabindingpt1\xaml\colors.xml"
/>
XmlDataProvider 的 Source 属性也可以指向标准 URL,以便创建对 XML API(如 RSS)的快速访问。
<StackPanel
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel.Resources>
<XmlDataProvider x:Key="MyRSS"
Source="http://adoguy.com/RSS"
/>
</StackPanel.Resources>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
XML Example
</TextBlock>
<ListBox Width="500" Height="300"
ItemsSource="{Binding Source={StaticResource MyRSS},
XPath=//item/title}">
</ListBox>
</StackPanel>
通过调用 RSS 源,我可以创建一个页面,以在 ListBox 中快速列出博客的主题,如图 6 所示。
图 6。 我的博客主题列表
使用 ObjectDataProvider
有时需要绑定到 .NET 对象。 这是 ObjectDataProvider 的用武之地。 此数据访问接口允许你为 .NET 数据类型创建绑定。
例如,我们可以在 .NET 中创建一个简单的字符串集合,如下所示。
public class MyStrings : List<String>
{
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 文档中的处理指令,通过将命名空间指定为 xmlns 声明,将 CLR 对象的整个命名空间添加到文档支持的类型。 例如,我们可以将整个命名空间的类映射到 XAML 中,如下所示。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Simple Source Binding"
xmlns:local="clr-namespace:XamlExamples"
x:Class="XamlExamples.SimpleSource"
>
<!-- ... -->
</Window>
若要从外部程序集导入类,可以指定 xmlns 声明,但指定程序集名称,如下所示。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Simple Source Binding"
xmlns:sys="clr-namespace:System,assembly=mscorlib"
x:Class="XamlExamples.SimpleSource"
>
<!-- ... -->
</Window>
导入类型后,可以使用 ObjectDataProvider 从这些类型之一指定数据源。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Simple Source Binding"
xmlns:local="clr-namespace:XamlExamples"
x:Class="XamlExamples.SimpleSource"
>
<Window.Resources>
<ObjectDataProvider x:Key="MyStringData" ObjectType="{x:Type local:MyStrings}" />
</Window.Resources>
<StackPanel>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
Simple Source Example
</TextBlock>
<ListBox Name="theListBox" Width="200" Height="300"
ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
</StackPanel>
</Window>
还可以通过指定具有命名空间名称和要使用的类型的 XAML 元素来创建资源,如下所示。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Simple Source Binding"
xmlns:local="clr-namespace:XamlExamples"
x:Class="XamlExamples.SimpleSource"
>
<Window.Resources>
<local:MyStrings x:Key="MyStringData" />
</Window.Resources>
<StackPanel>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
Simple Source Example
</TextBlock>
<ListBox Name="theListBox" Width="200" Height="300"
ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
</StackPanel>
</Window>
此语法的工作方式与 ObjectDataSource 类似,但使用起来要简单一些。 导入命名空间后,可以通过指定类的名称来添加引用数据源类的资源, (例如 MyStrings) 。 数据绑定与前面的示例相同,因为 XAML 代码并不关心它是哪种类型的数据源,只是考虑它是数据源。
绑定模式
在大多数情况下,你会希望 绑定 是双向绑定。 Binding 对象支持多种模式以支持不同的用例,如表 1 所示。
表 1. 支持的绑定模式
绑定模式 | 说明 |
---|---|
TwoWay | 以双向方式将更改从绑定控件或绑定源移动到其他控件。 (这是默认模式。) |
OneWay | 仅将更改从源移动到 控件。 源中发生更改时,绑定控件的数据将更改。 |
一次性 | 数据仅在启动时绑定,在控件首次填充数据后,将忽略对源的更改。 |
只需在标记中包含 模式即可指定模式,如下所示。
{Binding ElementName=theTextBox, Path=Text, Mode=OneTime}
查看双向绑定工作原理的一种方法是创建包含两个文本框的画布,一个文本框绑定到另一个文本框。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<Canvas>
<TextBox Name="theTextBox" Text="Hello" />
<TextBox Canvas.Top="25"
Text="{Binding ElementName=theTextBox, Path=Text, Mode=TwoWay}" />
</Canvas>
</Window>
如果将此代码粘贴到 SDK 附带的 XAMLPad 工具中,应注意到源文本框会在你键入时更新绑定文本框,但仅当绑定控件失去焦点时,才会从绑定控件更新到源代码管理。 如果将 模式 更改为 OneWay 或 OneTime,可以看到这些不同的模式如何更改绑定的工作方式。
控制绑定时间
除了 模式,还可以使用 UpdateSourceTrigger 指定绑定推送更改的时间。 可以通过指定 UpdateSourceTrigger 类型来指定绑定仅在指定时间进行更改。
{Binding ElementName=theTextBox, Path=Text, UpdateSourceTrigger=LostFocus}
UpdateSourceTrigger 属性指定何时使用更改更新源。 这仅适用于 Mode=TwoWay 绑定 (这是默认) 。 表 2 中显示了 UpdateSourceTrigger 的有效值。
表 2. UpdateSourceTrigger 值
UpdateSourceTrigger | 说明 |
---|---|
明确 | 仅通过显式调用 BindingExpression.UpdateSource 方法更新源。 |
LostFocus | 源在绑定控件失去焦点时更新。 |
PropertyChanged | 每次属性更改时,更改都会更新到源。 此选项为默认行为。 |
使用 DataContext
本文要介绍的最后一个概念是如何使用 DataContext。 DataContext 专门用于指定将某个容器中的所有控件绑定到公共对象。
例如,以下示例中有一个 Canvas,该 画布 将显示 XML 文档中特定节点的值和文本。
<StackPanel
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel.Resources>
<XmlDataProvider x:Key="FavoriteColors">
<Colors >
<Color ID="1">Blue</Color>
<Color ID="2">Black</Color>
<Color ID="3">Green</Color>
<Color ID="4">Red</Color>
</Colors>
</XmlDataProvider>
</StackPanel.Resources>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
XML DataContext Example
</TextBlock>
<Canvas DataContext="{Binding Source={StaticResource FavoriteColors}, XPath='/Colors/Color[@ID=2]'}">
<TextBlock Text="{Binding XPath=@ID}" />
<TextBlock Canvas.Top="25" Text="{Binding XPath=.}" />
</Canvas>
</StackPanel>
通过将 DataContext 设置为 XML 文档 (和特定的 XPath 表达式) ,我们告诉 Canvas ,其中不包含 Source 的所有控件都可以使用容器的 DataContext。 这样,我们只需指定 XPath 表达式即可绑定 TextBlock。 请注意,每个 TextBlock中的 XPath 表达式都是相对的 XPath 表达式。 这与对象绑定相同。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Simple Source Binding"
x:Class="XamlExamples.SimpleSource"
>
<Window.Resources>
<ObjectDataProvider TypeName="XamlExamples.MyStrings, XamlExamples"
x:Key="MyStringData" />
</Window.Resources>
<StackPanel>
<TextBlock HorizontalAlignment="Center"
FontWeight="Bold">
Object DataContext Example
</TextBlock>
<Canvas DataContext="{Binding Source={StaticResource MyStringData}}">
<TextBlock Text="{Binding Path=Length}" />
<TextBlock Canvas.Top="25" Text="{Binding Path=Item[0]}" />
</Canvas>
</StackPanel>
</Window>
使用 对象而不是 XML 只是意味着要使用 Path 表达式而不是 XPath 表达式。
我们在哪?
我们已经了解了如何使用 Binding 对象直接在 XAML 中执行数据绑定,无论是在简写版本还是长手版本中。 通过使用 XML 或对象数据提供程序,我们可以绑定到应用程序中不同类型的对象。 我们还了解了如何使用 Binding 对象的 ElementName 语法绑定到其他控件。 在本系列的下一部分中,我将展示如何使用自己的对象或 .NET 数据容器 ((例如 DataSources 和 DataSets) )获取此信息并绑定到实际数据库数据。
参考
- WinFX SDK
- 编程Windows Presentation Foundation,作者:Chris Sells 和 Ian Griffiths