[四] Binding

所有内容均出自于《深入浅出WPF》一书,其作者在b站也有相关视频,本文为个人读后总结,仅供参考

WPF 最重要的部分,灵魂所在,当连接一端的数据发生变化时,他会自动的在另一端刷新数据,它的存在相当于 web 中的前后端分离,至此,设计师只管UI,开发者只管业务逻辑,binding 成为它们中的桥梁,一端连接 UI,一端连接业务,重要的是,这都是自动的,这个桥梁不需要工程师去维护和设计,由此开始数据驱动UI

Bing的基础使用

binding: 翻译为 绑定,关键为 ,原意中还包含 关联 的意思

binding是桥梁,两端分别是 (source 从哪里来) ,目标(target 到哪里去),一般情况下,binding负责把逻辑层的数据运输到 UI 层,即数据驱动 UI

演示:

1.首先准备一个 Stu 类,这个类的 实例 将作为数据源,同时由于 binding 是一种自动机制,可以自动把变化传递给 UI,但是需要数据在变化是通知它一声,所以这里的类需要继承 INotifyPropertyChanged 通知类,当数据变化时,变化的属性 将会发出 PropertyChanged 事件,binding 会监听这个事件。

class Stu : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;private string name;public string Name{get { return name; }set { name = value;if (PropertyChanged != null){PropertyChanged.Invoke(this,new PropertyChangedEventArgs("Name"));}}}}

建立前端页面,后台建立binding 对象,然后把binding 绑到UI上

// UI
<StackPanel><TextBox x:Name="tb" Margin="5"/><Button Content="添加" Click="Button_Click" Margin="5" /></StackPanel>
//后台代码Stu stu = new Stu();public MainWindow(){InitializeComponent();Binding binding = new Binding();   //创建 binding 对象binding.Source = stu;              //为 binding 添加数据源binding.Path = new PropertyPath("Name"); //Path 是指我要绑定数据源中的哪一个属性,他的类型是 PropertyPath ,所以我们也new 一个                                                   //  PropertyPath,并指向 Name 属性       //通过 BindingOperations 把 binding 设置到Textbox上 ,这里要注意的是,binding 虽然是桥梁,但它不是一边连接数据源,一边连接目标,而是binding 连接数据源,然后把 binding 添加到目标上BindingOperations.SetBinding(this.tb,TextBox.TextProperty,binding); }private void Button_Click(object sender, RoutedEventArgs e){stu.Name += "hello"; //点击按钮,数据变化,通知 binding, 传递到 UI,UI变化}

效果:

补充:

把数据源和目标连接到一起使用了 BindingOperations.SetBinding(),现在解析一下

  • 第一个参数:指定 binding 的目标 ,这里就指定了 tb (textbox)
  • 第二个参数:指定数据要运输到目标的那个属性上,与binding 的 Path 很像, 这里接受一个 DependencyProperty 对象(依赖对象),他是一个比较特殊的对象,专门用来和 binding 联动,这一类属性就可以被数据驱动, UI 的控件基本都实现了这个属性,也可以自定义依赖属性
  • 第三个参数:指定那个 binding 实例将数据源和目标联系起来

Binding 的源(source)

指定 binding 的源包括指定 source 和 path

binding 数据源的要求:

  • Object 对象
  • 属性公开 (可以被访问到)

控件作为 binding的源 + binding 扩展标记的用法

<StackPanel><TextBox Text="{Binding ElementName=slider1, Path=Value}" Margin="10"/><Slider x:Name="slider1" Maximum="100" Margin="10"/></StackPanel>

控件作为 binding的源 需要使用 ElementName 来指定源

控制 binding 的方向及数据更新

控制数据流动方向: mode 属性,该类型是 Binding 枚举类

**数据更新:**在默认情况下,只有文本框失去焦点,数据才会更新,控制数据更新的的是 UpdateSourceTrigger 属性,它的类型是 UpdateSourceTrigger 枚举类,当把值改为 PropertyChanged 时,就可以实现实时变化了

演示:

这里将TextBox 的 Text 属性和 Slider 的 Value 属性绑定,并且设置 mode 为双向,UpdateSourceTrigger=PropertyChanged 实时更新,当我们滑动滑块时,文本框中的数值就会发生变化,并且一旦在文本框中修改值,立即就能同步到 salider 上

 <TextBox Text="{Binding ElementName=slider1,Path=Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="5"/><Slider x:Name="slider1" Maximum="100" Margin="5"/>

Binding 的路径

Path 用于指定我们需要绑定数据源的哪个属性

Path 的类型是

1.Path 的不同写法:

 //xmal: <TextBox Text="{Binding ElementName=slider1,Path=Value}"/>//c#Binding binding = new Binding() { Path = new PropertyPath("Value"), Source = slider1 };this.textBox.SetBinding(TextBox.TextProperty, binding);   //c# 简写 Binding 有很多重载,拥有直接接受path参数的构造器Binding binding = new Binding("Value") {  Source = slider1 };this.textBox.SetBinding(TextBox.TextProperty, binding);// 继续简化this.textBox.SetBinding(TextBox.TextProperty, new Binding("Value") {  Source = slider1 });

2.Path 支持多级路径

 // 通过 . 号可以像后台代码一样逐级往下点 <TextBox x:Name="textBox" Text="{Binding ElementName=tb1,Path=Text.Length,Mode=OneWay}"/><TextBox x:Name="tb1"/>//等效 c# 代码Binding binding = new Binding("Text.Length") {  Source = tb1 };this.textBox.SetBinding(TextBox.TextProperty, binding);     //集合类型的索引器又称为带参属性,只要是属性就可以作为 Path//xaml:<TextBox x:Name="textBox" Text="{Binding ElementName=tb1,Path=Text.[2],Mode=OneWay}"/><TextBox x:Name="tb1"/>//c#Binding binding = new Binding("Text.[2]") {  Source = tb1 };this.textBox.SetBinding(TextBox.TextProperty, binding);//简写 后台同理<TextBox x:Name="textBox" Text="{Binding ElementName=tb1,Path=Text[2],Mode=OneWay}"/><TextBox x:Name="tb1"/>

3.Path 支持集合

Path 支持多级路径,那么同样扩展一下,集合也可以使用,多级集合也可以

简单使用:

//xaml:
<StackPanel><TextBox x:Name="tb1" Margin="5"/><TextBox x:Name="tb2" Margin="5"/><TextBox x:Name="tb3" Margin="5"/>
</StackPanel>
//c#List<string> list = new List<string>() { "Hello", "Boy" };this.tb1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = list });this.tb2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = list, Mode = BindingMode.OneWay });this.tb3.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = list, Mode = BindingMode.OneWay });

效果:

进阶 – 集合的集合:

public MainWindow(){InitializeComponent();County county = new County() { Name = "中国", citys = new List<City>() {  new City() { Name = "西安" } , new City() { Name = "汉中" }} };List<County> list = new List<County>() { county};this.tb1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = list });this.tb2.SetBinding(TextBox.TextProperty, new Binding("/citys.Name") { Source = list});}}class County {public string Name { get; set; }public List<City> citys { get; set; }}class City {public string Name { get; set; }}

可以省略 Path 的情况

在数据源本身就是数据的情况下,就可以省略 path 比如 string 字符串示例本身就是数据,在zaml中,此时 path 可以用 . 代替。也可以直接不写,但是在 后台代码中,path 就只能使用 . 。

 <Window.Resources><c:String x:Key="str">Hello</c:String></Window.Resources><StackPanel><TextBlock Text="{Binding Path=.,Source={StaticResource ResourceKey=str}}"></TextBlock></StackPanel>

为 binding 指定源的几种方式

上面是如何通过 path 寻找属性,现在我们关注如何指定数据 source

binding 的源是数据的来源,只要一个对象包含数据并且能通过属性把数据暴漏出来,就可以作为 binding 的源,这里不过多解释,纯做记录,加粗表示个人用的较多

  • 普通的单个对象:包括 .net自带类型的的对象和自定义对象,如果类型实现了 INotifyPropertyChange 对象,就可以激发事件通知 bInding 更新
  • 集合对象:包括 数组 List 等,经常把此类数据作为 ItemControl 派生类的数据源使用,一般是赋给ItemSource
  • ADO.Net数据对象:包括DataTable 和 DataView 等
  • XmlDataProvider 把XML 数据指定为数据源:XML 使用广泛,尤其在级联式的控件中就可以把 XML作为源
  • 使用 Linq 检索结果作为源:Linq 类似于lamda表达式,在指定源时可以使用linq 来简化操作
  • 把依赖对象指定为 Source :前面有讲到,依赖属性是比较特殊的属性,专门用来和Binding联动,既可以作为目标,也可以作为源
  • 把容器的 DateContext 作为源:在没有指定源时, binding 会沿着控件树向上寻找Source
  • 通过 ElementName 指定 Source:在c#代码中可以直接指定对象作为源,但是 zaml 中无法访问对象,可以使用 ElementName 指定对象的名字
  • 通过 Binding 的 RelativeSource :把自己或者自己的属性指定为自己的源
  • 把 ObjectDataProvider 对象指定为源:特殊,把方法的返回值作为源,使用时需要创建ObjectDataProvider 对象,和方法所属类对象,把这个类传给ObjectDataProvider 并设定参数,就可以使用ObjectDataProvider 对象了

binding 没有 source 的情况

前面说过,WPF 的控件是一棵树,**每一个节点都有一个 DateContext 的属性,**当控件没有指定 source 时,他就会寻找沿着这棵树一直往上找 DateContext 的属性,看里面有没有对应的属性,找到就返回,没有找到就一直延续,直到树根还没找到,那就没有数据

 <Grid><StackPanel ><StackPanel.DataContext><local:Stu Name="Hello" Age="23"></local:Stu></StackPanel.DataContext><TextBox Text="{Binding Path=Name}" Margin="5"> </TextBox><TextBox Text="{Binding Path=Age}" Margin="5"></TextBox></StackPanel></Grid>

  • Binding 本身也有 path为参数的构造函数,所以在只有一个 path 时可以省略
 <Grid><StackPanel ><StackPanel.DataContext><local:Stu Name="Hello" Age="23"></local:Stu></StackPanel.DataContext><TextBox Text="{Binding Name}" Margin="5"> </TextBox><TextBox Text="{Binding Age}" Margin="5"></TextBox></StackPanel></Grid>
  • path 本身就是数据,不需要通过属性暴漏数据时**,可以用 . ,也可以省略**
 <Grid><StackPanel ><StackPanel.DataContext><c:String >Hello</c:String></StackPanel.DataContext><TextBox Text="{Binding}" Margin="5"> </TextBox><TextBox Text="{Binding}" Margin="5"></TextBox></StackPanel></Grid>

现在来细看一下指定源的几种方式

1.集合对象

  1. WPF 列表式控件派生自 ItemControl 类,继承了 ItemSource 的这个属性,**而 ItemSource 属性可以接受一个 IEnumerable 类型的值 **(可以接受集合的原因)
  2. 并且 ItemControl 的派生类都具有他们的的条目容器,比如 LIstBox 的条目容器是 ListBoxItem

演示:

//zaml:
<StackPanel Background="AliceBlue"><TextBox x:Name="tb1" Margin="5" /><ListBox x:Name="lb1" Margin="5"/></StackPanel>
//c#
InitializeComponent();
List<Stu> stus = new List<Stu>()
{new Stu(){  ID = 1, Name = "Tim"},new Stu(){  ID = 2, Name = "LIk"},
};
this.lb1.ItemsSource = stus;
this.lb1.DisplayMemberPath = "Name";Binding binding = new Binding("SelectedItem.ID") { Source = this.lb1 };
this.tb1.SetBinding(TextBox.TextProperty, binding);
//实体类
class Stu
{public int ID { get; set; }public String Name { get; set; }
}

给ItemsSource指定集合数据源,路径设置为 “Name”, TextBox 绑定ListBox 的 SelectedItem.ID,显示被选中的item的对象(Stu)的 ID

在 ItemsSource 中没看见 Binding 但是却实现了 binding 的效果,事实上,当DisplayMemberPath被赋值时,就会自动创建 Binding 并以DisplayMemberPath的值作为 path, 创建的 Binding 数据源就是 List中的每一个对象,path 就是DisplayMemberPath的值,目标就是 每一个 ListBoxItem(容器),默认情况下 ListBoxItem 的内部就是一个 TextBox,所以 Binding 实际绑定的是ListBoxItem下的TextBox

事实上大概就是下面这个样子,效果和 指定DisplayMemberPath后一样

<ListBox x:Name="lb1" Margin="5"><ListBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding Name}"/></DataTemplate></ListBox.ItemTemplate>
</ListBox>

在使用集合类型的控件时,一般会使用 ObservableCollection 替代List ,因为 ObservableCollection 自带通知

2. XmlDataProvider 把XML 数据指定为数据源

.net 提供了Dom(Document Object Mode 文档对象类型) 和 LINQ (Language-Integreted Query 语言集成查询)两种类库操作xml

这里以dom 为准

Binding 数据转换和校验 - MultiBinding(多路 Binding)

 </DataTemplate>
</ListBox.ItemTemplate>

```

在使用集合类型的控件时,一般会使用 ObservableCollection 替代List ,因为 ObservableCollection 自带通知

2. XmlDataProvider 把XML 数据指定为数据源

.net 提供了Dom(Document Object Mode 文档对象类型) 和 LINQ (Language-Integreted Query 语言集成查询)两种类库操作xml

这里以dom 为准

Binding 数据转换和校验 - MultiBinding(多路 Binding)

MultiBinding(多路 Binding) 和单 binding 并无区别,就是把多个 binding 集中在一起,统一操作,比如为 MultiBinding 设置一个校验器,他就可以应用到所有添加的 单个 binding 上

[四] WPF灵魂-Binding相关推荐

  1. WPF入门第六篇 WPF的Binding

    WPF的Binding 在传统的Windows软件中,大部分都是UI驱动程序的模式,也可以说事件驱动程序.WPF作为Winform的升级,它把UI驱动程序彻底改变了,核心回到了数据驱动程序的模式上面, ...

  2. WPF中Binding使用StringFormat格式化字符串方法

    原文:WPF中Binding使用StringFormat格式化字符串方法 货币格式 <TextBlock Text="{Binding Price, StringFormat={}{0 ...

  3. WPF之Binding(转)

    WPF之Binding Binding即绑定,听上去像一个音译词,很有趣,我们生活中常用的类似还有一个词,叫want to,我们叫妄图,只不过略加了感情色彩,扯远了,回到正题说绑定. 感觉这个东西在W ...

  4. WPF的binding

    深入浅出WPF之Binding的使用(一) 在WPF中Binding可以比作数据的桥梁,桥梁的两端分别是Binding的源(Source)和目标(Target).一般情况下,Binding源是逻辑层对 ...

  5. 深入浅出WPF之Binding的使用(一)

    from:   http://www.cnblogs.com/akwwl/p/3421005.html 在WPF中Binding可以比作数据的桥梁,桥梁的两端分别是Binding的源(Source)和 ...

  6. WPF 关于Binding

    命名空间:System.Windows.Data 作用:提供对绑定定义的高级访问,该绑定连接绑定目标对象(通常为 WPF 元素)的属性和任何数据源(例如数据库.XML 文件,或包含数据的任何对象).在 ...

  7. 【转载】wpf数据绑定binding与INotifyPropertyChanged

    WPF数据绑定号称是:数据变化会通过界面更新数据,这对新手而言,绝对是个误区,在我听说这句话的时候,我真是高兴,用了以后才发现其实没有那么美.要实现前面号称的特性,需要三个条件:1.进行绑定,2.绑定 ...

  8. WPF之Binding的三种简单写法

    环境 类代码 public class Person:INotifyPropertyChanged { private string name; public string Name { get { ...

  9. 深入浅出WPF之Binding的使用(二)

    from:    http://www.cnblogs.com/akwwl/p/3421250.html 在上一篇中介绍了Binding的基本绑定方法,这一篇中我们在深入的介绍Binding的其他用法 ...

最新文章

  1. WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)
  2. Vivado下几条 Verilog 综合规则
  3. C 语言编程 — 程序的装载与运行
  4. 插入区间Python解法
  5. windows路由表 重启后就还原了_绕过Apple id并可以随意重启的终极方案来了 (Windows下操作)...
  6. 张正友相机标定Opencv实现以及标定流程标定结果评价图像矫正流程解析(附标定程序和棋盘图)
  7. 【C语言】第八章 地址操作与指针 题解
  8. jconsole 里的线程编号一直在增加_第三章_运行时数据区概述及线程
  9. labelme标注工具实现json标注数据批量转换
  10. 360数科张家兴:金融科技的本质是线上化和自动化
  11. git 小札 - 流程总览
  12. WebStorm 2018破解版
  13. devcon命令开启启用/禁用端口
  14. xp自带打印驱动相关
  15. 吉他录音混音教程入门|连这些录音知识都不懂,以后还怎么“混”?| MZD Studios
  16. 联通光纤服务器没有响应怎么办,联通网速不稳定(联通光纤不稳定解决方法)
  17. pdf旋转后如何保存?操作工具有这些
  18. [转]30个总结JVM虚拟机的技术文排版好(收藏版)
  19. vue-qr 自动生成二维码+logo图片
  20. 电解电容的ESR到底是多少呢?

热门文章

  1. GPS 授时天线安装规范
  2. 音乐类APP的耗电量测试
  3. ./ts_calibrate: error while loading shared libraries: /tslib/lib/libts-0.0.s
  4. 一起学CICD 04.gitlab+jenkins+maven简单构建
  5. Maven仓库配置163源
  6. 2023 智能AI在线益智五子棋网站源码
  7. 软件工程师最热门:Indeed 发布 2017 年最佳职位
  8. CDC:跨时钟域处理
  9. STM32F105实现U盘IAP升级程序
  10. 单片机七阶音符_单片机演奏音乐(F调3个8度7音阶)程序+Proteus仿真