引用自:https://msdn.microsoft.com/zh-cn/magazine/cc163299.aspx
 数据点: WPF 中的数据绑定
数据点
WPF 中的数据绑定
John Papa

代码下载位置: DataPoints2007_12.exe (161 KB) 
Browse the Code Online

到目前为止,很多人都知道使用 Windows® Presentation Foundation (WPF) 可以轻松地设计强大的用户界面。但是您可能并不知道它还提供了强大的数据绑定功能。使用 WPF,可以通过利用 Microsoft® .NET Framework 代码、XAML 或两者的组合进行数据操作。您可以绑定控件、公共属性、XML 或对象,从而使数据绑定比以前更快捷、灵活和简单。所以,让我们来看一下如何开始将控件绑定到您所选的数据源中。

数据绑定细节
要使用 WPF 数据绑定功能,您必须始终要有目标和源。绑定的目标可以是从 DependencyProperty 派生而来的任何可访问属性或元素,例如 TextBox 控件的 Text 属性。绑定的源可以是任何公共属性,包括其他控件、公共语言运行库 (CLR) 对象、XAML 元素、ADO.NET Dataset、XML 片段等的属性。为了帮助您正确实现绑定,WPF 包含了两个特殊的提供程序:XmlDataProvider 和 ObjectDataProvider。
现在让我们看一下 WPF 数据绑定技术的工作原理,我将列举一些实用的示例来说明它们的用法。

创建简单的绑定
首先,我们来看一个简单的示例,该示例说明了如何将 TextBlock 的 Text 属性绑定到 ListBox 的选定项。图 1中的代码显示的是声明了六个 ListBoxItem 的 ListBox。该代码示例中的第二个 TextBlock 具有名为 Text(使用 XML 子元素 <TextBlock.Text> 在 XAML 属性元素语法中指定)的属性,它将包含 TextBlock 的文本。Text 属性声明了通过 <Binding> 标记与 ListBox 选定项的绑定。Binding 标记的 ElementName 属性指示 TextBlock 的 Text 属性要与其绑定的控件的名称。Path 属性指示我们将绑定到的元素(在本例中是 ListBox)的属性。此代码产生的结果是,如果从 ListBox 选择了一种颜色,该颜色的名称则会在 TextBlock 中显示。
  Figure 1 基本但详细的控件绑定
<StackPanel>     <TextBlock Width="248" Height="24" Text="Colors:"          TextWrapping="Wrap"/>     <ListBox x:Name="lbColor" Width="248" Height="56">         <ListBoxItem Content="Blue"/>         <ListBoxItem Content="Green"/>         <ListBoxItem Content="Yellow"/>         <ListBoxItem Content="Red"/>         <ListBoxItem Content="Purple"/>         <ListBoxItem Content="Orange"/>     </ListBox>     <TextBlock Width="248" Height="24" Text="You selected color:" />     <TextBlock Width="248" Height="24">         <TextBlock.Text>             <Binding ElementName="lbColor" Path="SelectedItem.Content"/>         </TextBlock.Text>     </TextBlock> </StackPanel>  
为了使用简单的语法来进行数据绑定,可以对图 1 中列出的代码稍加修改。例如,我们用下列代码段替代 TextBlock 的 <Binding> 标记:
<TextBlock Width="248" Height="24"      Text="{Binding ElementName=lbColor,      Path=SelectedItem.Content}" /> 
这种语法称为属性语法,它压缩了 TextBlock 的 Text 属性内部的数据绑定代码。基本上,Binding 标记会连同它的属性一起被归入大括号内。

绑定模式
我可以继续以上述示例为例,将 TextBlock 的背景色绑定到在 ListBox 中选择的颜色。以下代码可将 Background 属性添加到 TextBlock 中,并使用该属性的绑定语法将其绑定到 ListBox 中选定项的值:
<TextBlock Width="248" Height="24"  Text="{Binding ElementName=lbColor, Path=SelectedItem.Content,      Mode=OneWay}"  x:Name="tbSelectedColor"  Background="{Binding ElementName=lbColor, Path=SelectedItem.Content,      Mode=OneWay}"/> 
如果用户在 ListBox 中选择了一种颜色,那么该颜色的名称就会出现在 TextBlock 中,并且 TextBlock 的背景色会变为选定的颜色(请参见图 2)。
图 2 将一个源绑定到两个目标 
请注意前一个示例中将 Mode 属性设为 OneWay 的语句。Mode 属性用于定义绑定模式,它将决定数据如何在源和目标之间流动。除 OneWay 之外,还有另外三种绑定模式:OneTime、OneWayToSource 和 TwoWay。
正如前面的代码段中所示,使用 OneWay 绑定时,每当源发生变化,数据就会从源流向目标。尽管我在示例中显式指定了此绑定模式,但其实 OneWay 绑定是 TextBlock 的 Text 属性的默认绑定模式,无需对其指定。和 OneWay 绑定一样,OneTime 绑定也会将数据从源发送到目标;但是,仅当启动了应用程序或 DataContext 发生更改时才会如此操作,因此,它不会侦听源中的更改通知。与 OneWay 和 OneTime 绑定不同,OneWayToSource 绑定会将数据从目标发送到源。最后,TwoWay 绑定会将源数据发送到目标,但如果目标属性的值发生变化,则会将它们发回给源。
在上述示例中,我使用了 OneWay 绑定,因为我希望只要 ListBox 选择发生变化,就将源(选定的 ListBoxItem)发送到 TextBlock。我不希望 TextBlock 的更改再回到 ListBox。当然,用户无法编辑 TextBlock。如果我想使用 TwoWay 绑定,可以将 TextBox 添加到此代码中,将其文本和背景色绑定到 ListBox,并将 Mode 属性设为 TwoWay。用户在 ListBox 中选择一种颜色后,该颜色就会显示在 TextBox 中,并且其背景色会相应变化。如果该用户在 TextBox 中键入了一种颜色(例如蓝绿色),ListBox 中的颜色名称就会更新(从目标到源),反过来,因为 ListBox 已经更新,所以此新值就会被发送到绑定到 ListBox 的 SelectedItem 属性的所有元素。这意味着 TextBlock 也会更新其颜色,并且将其文本值设置为该新的颜色(请参见图 3)。
图 3 运行中的 TwoWay 绑定 
下面是我刚才用来将 TextBlock (OneWay) 和 TextBox (TwoWay) 绑定到 ListBox 的代码:
<TextBlock Width="248" Height="24"      Text="{Binding ElementName=lbColor, Path=SelectedItem.Content,     Mode=OneWay}" x:Name="tbSelectedColor"      Background="{Binding ElementName=lbColor, Path=SelectedItem.Content,      Mode=OneWay}"/>  <TextBox Width="248" Height="24"      Text="{Binding ElementName=lbColor, Path=SelectedItem.Content,      Mode=TwoWay}" x:Name="txtSelectedColor"      Background="{Binding ElementName=lbColor, Path=SelectedItem.Content,      Mode=OneWay}"/> 
如果我将 TwoWay 模式改回到 OneWay,用户则可以编辑 TextBox 中的颜色,且不会导致更改过的值被发回给 ListBox。
选择合适的绑定模式非常重要。当我想向用户显示只读数据时,我通常会采用 OneWay 模式。当我希望用户可以更改控件中的数据,并且让该变化能在数据源(DataSet、对象、XML 或其他绑定控件)中体现出来时,我会使用 TwoWay 绑定。如果想让用户在数据源不将其数据绑定到目标的情况下更改数据源,我发现 OneWayToSource 是个不错的选择。我曾经接到一个任务,要求在只读控件中显示与加载屏幕时一样的数据状态。在这个任务中,我使用了 OneTime 绑定。通过使用 OneTime 绑定,一系列只读控件均被绑定到了数据,并且当用户与表单交互且数据源的值发生更改时,绑定控件仍保持不变。这为用户提供了一种比较所发生更改的方法。此外,当源没有实现 INotifyPropertyChanged 时,OneTime 绑定也是一个不错的选择。

绑定的时间
在上述示例中,TextBox 允许 TwoWay 绑定到在 ListBox 中选定的 ListBoxItem。这会使数据在 TextBox 失去焦点时从 TextBox 流回 ListBox。为了改变导致将数据发送回源的这种情况,可以为 UpdateSourceTrigger 指定值,它是用于定义何时更新源的绑定属性。可以为 UpdateSourceTrigger 设置三个值:Explicit、LostFocus 和 PropertyChanged。
如果将 UpdateSourceTrigger 设置为 Explicit,则不会更新源,除非从代码调用 BindingExpression.UpdateSource 方法。LostFocus 设置(TextBox 控件的默认值)指示源在目标控件失去焦点时才会更新。PropertyChanged 值指示目标会在目标控件的绑定属性每次发生更改时更新源。如果您想指示绑定的时间,该设置非常有用。

绑定到 XML
绑定到数据源(例如 XML)和对象同样也非常方便。图 4 显示了 XmlDataProvider 的示例,其中包含将用作数据源的颜色的嵌入式列表。XmlDataProvider 可用来绑定到 XML 文档或片断,该文档或片段既可以嵌入在 XmlDataProvider 标记中,也可以位于外部位置引用的文件中。
  Figure 4 XmlDataProvider
<StackPanel> <StackPanel.Resources> <XmlDataProvider x:Key="MoreColors" XPath="/colors">     <x:XData>         <colors >             <color name="pink"/>             <color name="white"/>             <color name="black"/>             <color name="cyan"/>             <color name="gray"/>             <color name="magenta"/>         </colors>     </x:XData> </XmlDataProvider>  
嵌入式 XML 内容必须置于 XmlDataProvider 内部的 <x:XData> 标记中,如图 4 所示。必须为 XmlDataProvider 提供 x:Key 值,以便数据绑定目标可对其进行引用。请注意,XPath 属性设置为“/colors”。此属性定义了将用作数据源的 XML 内容的级别。当绑定到可能包含在文件或数据库中的较大 XML 结构,且想要绑定的数据不是根元素时,这一属性会变得非常有用。
XmlDataProvider 是可放置到特定上下文资源内部的一种资源。如图 4 所示,已将 XmlDataProvider 定义为 StackPanel 上下文中的资源。这意味着 XmlDataProvider 将可用于该 StackPanel 内部的所有内容。设置资源的上下文有助于限制数据源向合适的区域公开。这使您可以在页面内分别为控件和支持资源创建定义明确的独立区域,从而提高可读性。
绑定到资源的语法与绑定到元素的语法略有不同。绑定到控件时,可以设置绑定的 ElementName 和 Path 属性。但是绑定到资源时,需要设置 Source 属性,由于我们是绑定到 XmlDataProvider,所以还要设置绑定的 XPath 属性。例如,下列代码可将 ListBox 的项绑定到 MoreColors 资源。将 Source 属性设置为资源,并将其指定为名为 MoreColors 的 StaticResource。XPath 属性指示项会绑定到 XML 数据源中 <color> 元素的名称属性:
<ListBox x:Name="lbColor" Width="248" Height="56"      IsSynchronizedWithCurrentItem="True"      ItemsSource="{Binding Source={StaticResource MoreColors},      XPath=color/@name}"> </ListBox> 
我在本例中指定了 StaticResource,因为 XML 不会发生更改。如果数据源发生了更改,则不会将这些更改发送到目标。DynamicResource 设置则表示相反的情况,即会将数据源的更改发送到目标。当引用系统主题、全球化语言或字体时,该设置非常有用。DynamicResource 将允许这些类型的设置被传送到与其动态绑定的所有 UI 元素中。
XmlDataProvider 也可以指向 XML 内容的外部源。例如,我有一个名为 colors.xml 的文件,其中包含我希望 ListBox 绑定到的颜色列表。我只需要将第二个 XmlDataProvider 资源添加到 StackPanel,并将其引向 XML 文件即可。请注意,我将 Source 属性设置为了 XML 文件的名称,并将 x:Key 设置为 Colors:
<XmlDataProvider x:Key="Colors" Source="Colors.xml" XPath="/colors"/>  
两个 XmlDataProvider 在同一个 StackPanel 中都作为资源而存在。我可以使 ListBox 将其本身绑定到这个新的资源,方法是更改 StaticResource 设置的名称:
<ListBox x:Name="lbColor" Width="248" Height="56"      IsSynchronizedWithCurrentItem="True"      ItemsSource="{Binding Source={StaticResource Colors},      XPath=color/@name}"> </ListBox> 

对象绑定和 DataTemplates
虽然 XmlDataProvider 对 XML 非常有用,但是当您想绑定到对象或对象列表时,可以创建 ObjectDataProvider 作为资源。ObjectDataProvider 的 ObjectType 指定将提供数据绑定源的对象,而 MethodName 则指示为获得数据而需调用的方法。例如,假设我有一个名为 PersonService 的类,该类使用一种名为 GetPersonList 的方法来返回列表 <Person>,那么 ObjectDataProvider 可能会如下所示:
<StackPanel.Resources> <ObjectDataProvider x:Key="persons"  ObjectType="{x:Type svc:PersonService}"  MethodName="GetPersonList"></ObjectDataProvider> </StackPanel.Resources> 
如果您想进行更全面的了解,本栏随附的代码中还包含了 PersonService 和 Person 类以及其他示例代码。
ObjectDataProvider 还可以使用许多其他属性。ConstructionParameters 属性允许您将参数传递给要调用的类的构造函数。此外,可以使用 MethodParameters 属性来指定参数,同时还可以使用 ObjectInstance 属性来指定现有的对象实例作为源。
如果希望异步检索数据,可以将 ObjectDataProvider 的 IsAsynchronous 属性设为 true。这样,用户将可以在等待数据填充绑定到 ObjectDataProvider 的源的目标控件时与屏幕进行交互。
在添加 ObjectDataProvider 时,必须限定数据源类的命名空间。在本例中,我必须将 xmlns 属性添加到 <Window> 标记中,以便 svc 快捷方式符合要求,并指示正确的命名空间:
xmlns:svc="clr-namespace:DataBindingWPF" 
既然数据源已通过 ObjectDataProvider 定义,接着我想将 ListBox 控件中的项绑定到此数据。我想在每个 ListBoxItem 中显示两行文本。第一行将以粗体显示 Person 实例的 FullName 属性,第二行将显示该实例的 Title 和 City。在 XAML 中,通过使用 DataTemplate,这是很容易实现的,DataTemplate 允许您定义可重用的数据可视化策略。
图 5 显示了完整的 XAML,其中将 DataTemplate 定义为在我指定的布局中显示 Person 信息。我设置了 DataTemplate 的 DataType 属性,以指示 DataTemplate 将会引用 Person 类类型。我没有在 DataTemplate 中指定真正的绑定,因为我会在 ListBox 控件中指定。通过省略绑定源,可对作用域内的当前 DataContext 执行绑定。
图 5 中,我将 ListBox 的 ItemsSource 属性设置为绑定到人员资源,以便我可以将数据绑定到 ListBox,而不用对它进行格式化。通过将 ItemTemplate 属性设置为 PersonLayout 资源(即 DataTemplate 的键名),可以正确显示数据。最终结果的屏幕如图 6 所示。
  Figure 5 对象绑定
<Window x:Class="DataBindingWPF.ObjectBinding" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:svc="clr-namespace:DataBindingWPF" Title="DataBindingWPF" Height="300" Width="300"> <StackPanel>     <StackPanel.Resources>         <ObjectDataProvider x:Key="persons"            ObjectType="{x:Type svc:PersonService}"            MethodName="GetPersonList" ></ObjectDataProvider>             <DataTemplate x:Key="personLayout" DataType="Person">                 <StackPanel Orientation="Vertical">                     <TextBlock Text="{Binding Path=FullName}"                              FontWeight="Bold" Foreground="Blue">                     </TextBlock>                 <StackPanel Orientation="Horizontal">                     <TextBlock Text="{Binding Path=Title}"></TextBlock>                     <TextBlock Text=", "></TextBlock>                     <TextBlock Text="{Binding Path=City}"></TextBlock>                 </StackPanel>             </StackPanel>         </DataTemplate>     </StackPanel.Resources>     <TextBlock></TextBlock>     <ListBox x:Name="lbPersons"              ItemsSource="{Binding Source={StaticResource persons}}"              ItemTemplate="{DynamicResource personLayout}"              IsSynchronizedWithCurrentItem="True"/> </StackPanel> </Window>  
图 6 使用 DataTemplate 

对数据进行排序
如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider。CollectionViewSource 则会成为数据源,并充当截取 ObjectDataProvider 中的数据的媒介,并提供排序、分组和筛选功能,然后将它传送到目标。
接着显示的 CollectionViewSource 将其 Source 属性设置为 ObjectDataProvider(人员)的资源名称。然后我通过指示排序依据的属性及其方向定义了数据的排序顺序:
<CollectionViewSource x:Key="personView"      Source="{Binding Source={StaticResource persons}}">     <CollectionViewSource.SortDescriptions>     <ComponentModel:SortDescription       PropertyName="City"      Direction="Ascending" />         <ComponentModel:SortDescription      PropertyName="FullName"      Direction="Descending" />     </CollectionViewSource.SortDescriptions> </CollectionViewSource> 
DataContext 可用来将容器控件内部的所有控件都绑定到数据源中。当您拥有多个控件,而且这些控件全部使用同一个绑定源时,这非常有用。如果为每个控件都指定了绑定源,那么代码可能会重复。相反,可以将容器控件的 DataContext 设置为绑定源,然后只需从所包含的控件中省略 Source 属性即可。例如,下面是一系列显式绑定到同一个绑定源的 TextBlock:
<StackPanel> <TextBlock Text="{Binding Source={StaticResource personView},      Path=FullName}"></TextBlock> <TextBlock Text="{Binding Source={StaticResource personView},      Path=Title}"></TextBlock> <TextBlock Text="{Binding Source={StaticResource personView},      Path=City}"></TextBlock> </StackPanel> 
以下是绑定到 DataContext 的三个相同的 TextBox,在此处,DataContext 反过来引用了该控件的 StackPanel 容器:
<StackPanel DataContext="{Binding Source={StaticResource personView}}" > <TextBlock Text="{Binding Path=FullName}"></TextBlock> <TextBlock Text="{Binding Path=Title}"></TextBlock> <TextBlock Text="{Binding Path=City}"></TextBlock> </StackPanel> 
如果该容器没有定义 DataContext,那么它会继续查找下一个外部嵌套容器,直到它找到当前的 DataContext 为止。

欢迎试用和反馈
WPF 数据绑定具有很大的灵活性,并且能够控制可被绑定的数据类型以及它的控制和显示方式。有了这么多的功能和选择,我相信您一定跃跃欲试。

请将您想向 John 询问的问题和提出的意见发送至 mmdata@microsoft.com.

John Papa 是 ASPSOFT (aspsoft.com) 的一名高级 .NET 顾问,也是一名棒球迷。夏季的夜晚,他大多时候都和家人及其忠实的狗 Kadi 一起为洋基队加油助威度过。John 是 C# 领域的一位 MVP,撰写过多本有关 ADO、XML 和 SQL Server 方面的书籍。他经常在行业会议(如 VSLive)上发表演讲,或者在 codebetter.com/blogs/john.papa 上撰写博客文章。

 

WPF中的数据绑定!!!的更多相关文章

  1. WPF入门教程系列十五——WPF中的数据绑定(一)

    使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...

  2. WPF中的数据绑定(初级)

    关于WPF中的数据绑定,初步探讨 数据绑定属于WPF中比较核心的范畴,以下是对WPF中数据绑定的一个初步探讨.个人感觉还是带有问题性质的叙述比较高效,也比较容易懂 第一,什么是数据绑定? 假定有这么一 ...

  3. WPF中的数据绑定

    WPF中的数据绑定 基础概念 System.Windows.Data.Binding,他会把两个对象(UI对象与UI对象之间,UI对象与.NET数据对象之间)按照指定的方式粘合在一起,并在他们之间建立 ...

  4. Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定)

    原文:Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定) ------------------------------ ...

  5. 【值转换器】 WPF中Image数据绑定Icon对象

    原文:[值转换器] WPF中Image数据绑定Icon对象        这是原来的代码:        <Image Source="{Binding MenuIcon}" ...

  6. WPF入门教程系列十八——WPF中的数据绑定(四)

    六.排序 如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会 ...

  7. 【翻译】WPF中的数据绑定表达式

    有很多文章讨论绑定的概念,并讲解如何使用StaticResources和DynamicResources绑定属性.这些概念使用WPF提供的数据绑定表达式.在本文中,让我们研究WPF提供的不同类型的数据 ...

  8. WPF入门教程系列十七——WPF中的数据绑定(三)

    四. XML数据绑定 这次我们来学习新的绑定知识,XML数据绑定.XmlDataProvider 用来绑定 XML 数据,该XML数据可以是嵌入.Xmal文件的 XmlDataProvider 标记中 ...

  9. WPF入门教程系列十六——WPF中的数据绑定(二)

    三.绑定模式 通过上一文章中的示例,学习了简单的绑定方式.在这里的示例,要学习一下绑定的模式,和模式的使用效果. 首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项,去改变TextBl ...

随机推荐

  1. TortoiseGit与GitHub项目关联设置

    一.常规克隆GitHub上的项目: 1.在本地硬盘上放置项目的地方上[右键]->[Git 克隆]->在[url地址]上输入https的GitHub的链接,然后就是等待完成,之后即可完成拉取 ...

  2. 百度地图学习(Ⅰ)-Android端地图的显示及简单应用

    ps:(1.地图应用一定要在真机测试: 2.Design By:Android Stdio: 3.百度地图官方参考链接(http://developer.baidu.com/map/index.php ...

  3. js事件委托的方式绑定详解

    js事件绑定 事件绑定,这里使用了冒泡的原理,从点击的元素开始,递归方式的向父元素传播事件,这样做的好处是对于大量要处理的元素,不必为每个元素都绑定事件,只需要在他们的父元素上绑定一次即可,提高性能. ...

  4. PHP框架中的日志系统

    现在在一家公司做PHP后台开发程序猿(我们组没有前端,做活动时会做前端的东西),刚开始到公司的时候花2个周赶出了一个前端加后台的活动(记得当时做不出来周末加了两天班...),到现在过去4个多月了,可以 ...

  5. 加州大学伯克利分校Stat2.2x Probability 概率初步学习笔记: Midterm

    Stat2.2x Probability(概率)课程由加州大学伯克利分校(University of California, Berkeley)于2014年在edX平台讲授. PDF笔记下载(Acad ...

  6. 简单说说Tk和Tcl

    开园第一个博客,简单说说Tk和Tcl. 我接触Tk和Tcl是在学习Python Tkinter时候,创建Tk对象,下面言归正传: Tcl:工具命令语言,英文全称为Tool Command Langua ...

  7. B2B电子商务网站技术框架

    一 设计原则 电子商务平台总体结构的设计应从体系.功能.信息.过程等各个方面保证整个电子商务平台总体目标的实现,以提高市场竞争能力.总体结构的设计应考虑以下设计原则: 快速响应原则:商机稍纵即逝,网站 ...

  8. python数据库操作常用功能使用详解(创建表/插入数据/获取数据)

    实例1.取得MYSQL版本 复制代码 代码如下: # -*- coding: UTF-8 -*-#安装MYSQL DB for pythonimport MySQLdb as mdbcon = Non ...

  9. C# 文件操作大全

    1.创建文件夹//using System.IO;Directory.CreateDirectory(%%1); 2.创建文件//using System.IO;File.Create(%%1); 3 ...

  10. linux curl 命令详解,以及实例

    linux curl是一个利用URL规则在命令行下工作的文件传输工具.它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称url为下载工具. 一,curl命令参数,有好多我没有用过,也不知道翻 ...