1.Binding的基础概念
将Source的数据传递给Target,或者Target的数据传递给Source

2.Binding最简单的绑定
创建一个普通的Student类,包含一个Name属性,当作Source
让这个类继承INotifyPropertyChanged接口,实现该接口,即声明
一个PropertyChangedEventHandler事件

 public class Student:INotifyPropertyChanged {private string  name;public string Name{get { return name; }set { name = value;if (PropertyChanged!=null){this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));}}}public event PropertyChangedEventHandler PropertyChanged;`在这里插入代码片`}事件信息参数为要修改的Name属性。
然后在XAML中声明一个TextBox与Button,TextBox作为Target,Button修改Source的Name。可以在C#中做绑定```csharp
this.text1.SetBinding(TextBox.TextProperty,new Binding("Name") { Source=stu});

也可以在XAML中做绑定,XAML语言是不能直接访问对象的,只能通过ElementName=sourceName,即通过设置ElementName,对象名字来访问对象

<TextBox x:Name="text1" Margin="5" Text="{Binding Path=Value,ElementName=slider1}"/>
<Slider x:Name="slider1" Margin="5" Maximum="100" Minimum="0" />

XAML中进行绑定最好是简单的绑定,只有Source Path 这种是比较合适的,当涉及到数据校验或者数据转换的时候,需要在C#的代码中实现较为合适。
可以看出的是XAML中进行Binding的方式是对某一属性使用扩展方法进行赋值,赋值的内容为"{Binding Path= , ElementName =,…}"

3.没有Path的绑定
Source本身就是一个值的时候,即Source为Path的时候可以省略掉Path

<StackPanel.Resources><sys:String x:Key="myString">菩提本无树,明镜亦非台。本来无一物,何处惹尘埃。</sys:String></StackPanel.Resources><TextBlock x:Name="textBlock1" TextWrapping="Wrap" Text="{Binding Source={StaticResource ResourceKey=myString}}" FontSize="16" Margin="5"/></StackPanel>

对应的C#绑定代码为
string mystring = “菩提本无树,明镜亦非台。本来无一物,何处惹尘埃。”;
this.textBlock1.SetBinding(TextBlock.TextProperty, new Binding(".") { Source = mystring });

4.作为Source的情况,当Source指定好之后,Path就可以比较简单的确认了,无论是Source本身还是其中的某一属性。
(1)普通的类(注意要实现INotifyPropertyChanged接口来通知binding数据更新),或者普通的控件都可以作为Source
(2)DataContext:所有的控件都有这个属性,当没有给这个属性赋值的时候,会根据UI树向上寻找有赋该值的控件,然后借用其值(依赖属性的定义)
先声明一个学生类

public class Student {public string Name { get; set; }public int Id { get; set; }public int Age { get; set; }}

注意不要声明字段,在XAML中为DatatContext中设置的时候读取不到字段。
XAML中设置TextBox与Student中类的属性进行绑定

<StackPanel Background="LightBlue"><StackPanel.DataContext><local:Student Name="Tim" Age="28" Id="6"/></StackPanel.DataContext><Grid><StackPanel><TextBox Text="{Binding Path=Name}" Margin="5"/><TextBox Text="{Binding Path=Id}" Margin="5"/><TextBox Text="{Binding Path=Age}" Margin="5"/></StackPanel></Grid></StackPanel>

这时候是没有指明Source的,声明绑定过后,会在UI树上寻找有该属性的控件然后绑定该属性的值。
例如:第一个TextBox 绑定的 Path是Name,这时候就会在UI树上找那个控件有对应的值,这时候发现 StackPanel中的DataContext有该值,则进行绑定。
另外比较特殊的是,如果Source即是Path则 可以直接写作Text="{Binding}" 这种既无Source也无Path的形式。
(3)关于链表式控件的绑定
链表式控件,可以像普通的绑定那样进行一对一的绑定。
并且链表式控件都有ItemsSource,该属性接收一个IEnumerable接口派送类的对象。并且链表式控件具有条目容器。当使用 ItemsSource接收数据时,就会为每个数据都准备条目容器,当作数据外衣使用。
做一个简单的例子:
XAML中声明一个链表式控件:

在C#中声明一个List,并且与listStudent进行绑定

 List<Student> students = new List<Student>{new Student(){ Id=0,Age=29,Name="tim"},new Student(){ Id=1,Age=26,Name="tom"},new Student(){ Id=2,Age=25,Name="lucy"},new Student(){ Id=3,Age=24,Name="jerry"},new Student(){ Id=4,Age=23,Name="nancy"},new Student(){ Id=5,Age=22,Name="mike"},};this.listStudent.ItemsSource = students;this.listStudent.DisplayMemberPath = "Name";

唯一的缺陷是这个条目容器是默认值的,只能显示一个值,当要同时显示Id,Age,Name的时候就需要自己设计条目容器ItemTemplate,DataTemplate

<ListBox x:Name="listStudent" Height="300" Width="500"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Path=Id}" Width="30"/><TextBlock Text="{Binding Path=Name}" Width="60"/><TextBlock Text="{Binding Path=Age}" Width="30"/></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox>

说完链表式控件作为Target使用的过程,可以作为链表式控件的Source的是IEnumrable的派送类。可以看到比较常用的场景有:
①ADO.NET读取的数据库的数据
ADO.NET类,常用来与数据库做交互使用。常见的工作是从数据库中读取数据到DataTable中,在把DataTable中的数据显示在UI上。
比较特殊的是DataTable不能直接绑定在链表式控件的ItemsSource上。一般是
DataTable dt=this.Load();
this.listName.DisplayMemberPath=“Name”;
this.listName.ItemsSource=dt.DefaultView;

DataTable的DefaultView中的值是DataView类型的对象实现了IEnumerable接口
为了更好的展示就使用ListView控件来展示,手动的设置条目容器的样式。XAML代码如下:

 <ListView x:Name="listViewName" Height="130" Margin="5"><ListView.View><GridView><GridViewColumn Header="TileName" Width="60" DisplayMemberBinding="{Binding Path=pathName}"/></GridView></ListView.View></ListView>

条目容器的设置是设置相关的View属性。View属性的值是GridView。GridView的属性值是Column。绑定的Target.Property也变成了DisplayMemberBinding。
绑定的Source还是ItemsSource。
已知的是DataTable是不能直接赋给ItemsSource的,但是可以赋给控件的DataContext,然后直接进行没有Source的绑定。
②XML数据
主要是XML数据读取转换成IEnumerable派送类这块,后续绑定和前面说的链表式控件的绑定过程一样。
使用的是XmlDataProvider类。

XmlDocument doc =new XmlDocument();
doc.Load(@"Path");XmlProvider xdp=new XmlProvider();
xdp.Document=doc;xdp.XPath=@"/tagName1/tagName2"this.listViewName.DataContext=xdp;
this.listViewName.SetBinding(ListViewItemsSourceProperty,new Binding());

设置条目容器的样式的时候的展示内容,在Xaml中需要注意的是,如果是Xml的Attribute要加@,不加的是子级元素

<GridViewColumn Header="TileName" Width="60" DisplayMemberBinding="{Binding XPath=@AttributepathName}"/>
<GridViewColumn Header="TileName" Width="60" DisplayMemberBinding="{Binding XPath=pathName}"/>

XML语言是很方便展示树形结构的数据。
③前面两种都可以通过 Linq语言直接处理之后变为IEnumerable类型的数据,直接赋给ItemsSource属性。
this,listViewName.ItemsSource= from list1 in listName Where … select stu;

关于数据库文件与Xml文件通过Linq处理的,单独列章分析。

5.有时候要绑定的Source是别人类库的东西,或者是通过别人封装好的方法的返回值,这时候就可以通过ObjectDataProvider来包装作为Binding源的数据对象。

ObjectDataProvider包装过程
ObjectDataProvider odp = new ObjectDataProvider();
odp.ObjectInstance = new ClassName();
odp.MethodName = "MethodName";
odp.MethodParameters.Add("Arg[0]");
odp.MethodParameters.Add("Arg[1]");

Demo:
设置一个Calculator类做加法运算

class Calculator {public string Add(string arg1, string arg2) {double x;double y;double z;if (double.TryParse(arg1,out x)&&double.TryParse(arg2,out y)){z = x + y;return z.ToString();}return "Input error";}}

使用ObjectDataProvider进行封装

ObjectDataProvider odp = new ObjectDataProvider();
odp.ObjectInstance = new Calculator();
odp.MethodName = "Add";
odp.MethodParameters.Add("0");
odp.MethodParameters.Add("0");

设置Binding:

<StackPanel Background="LightBlue"><TextBox x:Name="textArg1" Margin="5"/><TextBox x:Name="textArg2" Margin="5"/><TextBox x:Name="textArgResult" Margin="5"/></StackPanel>

C#中运行就调用的方法:

private void SetBinding() {ObjectDataProvider odp = new ObjectDataProvider();odp.ObjectInstance = new Calculator();odp.MethodName = "Add";odp.MethodParameters.Add("0");odp.MethodParameters.Add("0");Binding bindingToArg1 = new Binding("MethodParameters[0]") {Source = odp,BindsDirectlyToSource=true,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};Binding bindingToArg2 = new Binding("MethodParameters[1]"){Source = odp,BindsDirectlyToSource = true,UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged};Binding bindingToResult = new Binding(".") { Source = odp };this.textArg1.SetBinding(TextBox.TextProperty,bindingToArg1);this.textArg2.SetBinding(TextBox.TextProperty, bindingToArg2);this.textArgResult.SetBinding(TextBox.TextProperty, bindingToResult);}

6.Source为RelativeSource
先初始化该类

RelativeSource rs=new RelativeSource(RelativeSource.Mode....)
Binding binding=new Binding("Name"){RelativeSource=rs};
this.UIName.Setbingding(Property,binding);

初始化的Mode,为枚举类型,分别为PreviousData,TemplatedParent,Self和FindAncestor,前三个是创建RelativeSource实例,把实例的Mode是指为相应的值,然后返回这个实例。
Demo:

<StackPanel x:Name="s1" Background="LightBlue"><Grid x:Name="g1"><StackPanel x:Name="s2"><DockPanel x:Name="d1"><TextBox x:Name="t1"></TextBox></DockPanel></StackPanel></Grid></StackPanel>
若为FindAncestor则还要设置AncestorLevel和AncesType
RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);
rs.AncestorLevel = 1;
rs.AncestorType = typeof(Grid);
this.t1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource=rs});

如果是其他三个则可以直接使用:

RelativeSource rs = new RelativeSource(RelativeSourceMode.Self);
this.t1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource=rs});

7.Binding过程的数据校验
Binding数据校验主要是使用Binding.Validation.Add(ValidationRule)
参数为实现了ValidationRule的派生类。
Demo:

 class RangValidation : ValidationRule {public override ValidationResult Validate(object value, CultureInfo cultureInfo) {double d;if (double.TryParse(value.ToString(),out d)){if (d>0&&d<100){return new ValidationResult(true, null);}}return new ValidationResult(false, "Data is error");}}
private void SetBinding() {RangValidation rang = new RangValidation();rang.ValidatesOnTargetUpdated = true;Binding binding = new Binding();binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;binding.ValidationRules.Add(rang);binding.Source = this.slider1;binding.Path = new PropertyPath("Value");this.text1.SetBinding(TextBox.TextProperty, binding);}

如果要在UI树上通知校验后的信息,只需要把

Binding.ValidationOnNotifyDataErrors=true;

然后在需要显示的UI控件上做路由侦听。(路由事件的时候具体写)

8.Binding数据的转换
数据的传输很多时候要面对的问题是数据类型。
当Source Path与Target的类型不一样的时候,如slider的Value是Double,而Text是String。
一些简单的数据转换Binding会自动实现,像是Double->String。
遇到复杂的情况需要自己实现 Data Converter
即创建一个类实现IValueConverter接口的类

class DataConverterDemo : IValueConverter {public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {//转换value值,针对value值的不同返回想要的类型ClassName c1=(ClassName)value;switch (cl){case A:return oneTypeClass;default:break;     }}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {ClassName c1=(ClassName)value;switch (cl){case A:return oneTypeClass;default:break;     }}}
}

从Source->Target时调用Convert
从Target->Source时调用ConvertBack
使用的时候直接设置:

Binding.Converter=dataConcerter

9.MutilBinding

MutilBinding mb=new MutilBinding();
mb.MutilBindings.Add(new Binding());

另外这种多个Source绑定一个Target的数据类型转换器Data Converter要实现的是IMutilValueConverter接口,实现的方法同IValueConverter差不多,不过传递的第一个参数为object[] values。
MutilBindings.Add添加的时候是顺序敏感的。

整理《深入浅出WPF》

Binding的使用梳理相关推荐

  1. Docker容器学习梳理--日常操作总结

    使用Docker已有一段时间了,今天正好有空梳理下自己平时操作Docker时的一些命令和注意细节: Docker 命令帮助 $ sudo docker Commands:attach Attach t ...

  2. iOS面试必看,最全梳理

    序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了.今年,找过工作人可能会更深刻地体会到今年的就业形势不容乐观,加之,培训机构一火车地向用人单位输送iOS开发人员,打破了生态圈的动态 ...

  3. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

    同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProperty)只能拥有一个binding. 这一点可以通过设置bindi ...

  4. SpringCloud微框架系列整体模块梳理

    转载自:https://www.cnblogs.com/softidea/p/6498125.html SpringCloud微框架系列整体模块梳理 以下为Spring Cloud的核心功能: 分布式 ...

  5. mybatis源码过程学习梳理

    一.mybatis配置文件详情 在Spring中,是使用xml的配置文件或使用java代码对mybatis的连接属性,环境等进行配置的,我们先看一下mybatis中对配置文件中节点的要求. 通过myb ...

  6. Vue官方文档梳理-全局API

    Vue.extend 配置项data必须为function,否则配置无效.data的合并规则(可以看<Vue官方文档梳理-全局配置>)源码如下: 传入非function类型的data(上图 ...

  7. vue怎么把api 挂载到全局_深入理解Vue官方文档梳理之全局API

    Vue.extend 配置项data必须为function,否则配置无效.data的合并规则(可以看<Vue官方文档梳理-全局配置>)源码如下: 传入非function类型的data(上图 ...

  8. Android 源码梳理

    Android 源码梳理 前言 作为霜枫司机一年学习的总结,附上帅照一张. 目录 1. Android系统启动过程分析 2. Linux内核文件系统 3. Android进程间通信源码梳理 4. An ...

  9. 互联网公司iOS开发工程师面试必看(最全知识点梳理)

    序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了.今年,找过工作人可能会更深刻地体会到今年的就业形势不容乐观,加之,培训机构一火车地向用人单位输送iOS开发人员,打破了生态圈的动态 ...

  10. iOS面试问题全面梳理 --持续更新

    序言 目前,参加到iOS队伍的人是越来越多,形势不容乐观.为iOS应聘者梳理一下面试题,希望能助一臂之力! OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装.继承.多态. ...

最新文章

  1. Java线程池使用与原理
  2. python 用一个数组实现三个栈
  3. 如何理解Bounce Rate和Exit Rate
  4. 日记——2019-03-12
  5. TypeScript 官方决定全面采用 ESLint
  6. .NET下 Access与SQL Server的效率简易比较
  7. MYSQL 查看表定义的 4 种方法
  8. FULENT软件测试自学,fluent网格质量检查 - 仿真模拟 - 小木虫 - 学术 科研 互动社区...
  9. 再传喜讯,鸿雁中标杭州地铁3号线配电工程
  10. VS绿豆沙屏幕保护色参数设置
  11. python 求定积分
  12. js和java导出txt文件怎么打开文件_JS本地文件操作,JS读写txt文件
  13. 云计算和云服务器分别表示什么?
  14. head/tail/tail -f
  15. Openstack Ironic Bare metal 实操
  16. mysql员工请假流程表字段_“员工请假”流程及在线表单开发示例
  17. LSP 语言服务协议
  18. android setMargin失效不起作用
  19. 离散实验偏序关系满足实验报告C语言,离散数学实验三
  20. 分享一些我常用的游戏开发素材网站

热门文章

  1. SH-SSS丨《端到端音视频说话人日志网络》论文线上分享
  2. 小米android的手机根目录,手机网站根目录在哪?
  3. Goby - 新一代安全工具
  4. RO-data、RW-data、ZI-data的解释
  5. 带有风的诗词_带有风的诗句
  6. b5纸尺寸_【收藏款】平面设计标准尺寸规范总结
  7. 计算机重装后如何连接无线网络,电脑重装系统后怎么连接无线网络连接
  8. Why “the CUDA Samples are not meant for performance measurements”?
  9. UI设计需要使用哪些软件?推荐这5款
  10. Cassandra中Gossip具体实现方式