WPF学习笔记
《深⼊浅出WPF》学习笔记
第6章 深⼊浅出话Binding
6.2 Binding基础
如果把Binding⽐作数据的桥梁,那么它的两端分别是Binding的源(Source)和⽬标(Target)。⼀般源是逻辑层对象,⽬标是UI层控件对象.
我们可以控制源与⽬标是双向通⾏还是单向,还可以控制对数据放⾏的时机,还可以设置“关卡”转换数据类型或校验数据的正确性。
class Student
{
public string Name {get;set;}
public string Age {get;set;}
}
Path:如上所⽰,⼀个对象有多个属性,UI上关⼼哪个属性值的变化呢?这个属性就称为Binding的路径(Path)
PropertyChanged:让属性具备通知Binding值已变化的能⼒。作为数据源的类实现INotifyPropertyChanged接⼝。
using System.ComponentModel;
class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get { return name; }
set
{
name = value;
//激发事件
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
Binding的过程:
Student stu = new Student();
Binding binding = new Binding();
binding.Source = stu;
binding.Path = new PropertyPath("Name");
BindingOperations.BoxName,TextBox.TextProperty,binding);
主要是 源、路径、设置绑定
实际⼯作中,实施Binding的代码可能与上⾯不太⼀样,因为TextBox这类UI元素的基类FramewordElement对
BindingOperation.SetBinding(...)⽅法进⾏了封装,封装的结果也叫SetBinding,只是参数列表发送了变化
public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
{
return BindingOperations.SetBinding(this, dp, binding);
}
借助Binding类的构造器及C#3.0的对象初始化器语法简化上述代码
6.3 Binding的源与路径
源:只要是⼀个对象,并⾏通过属性(Property)公开⾃⼰的数据,它就能作为Binding的源
如果想让作为Binding源的对象具有⾃动通知Binding属性已改变的能⼒,就需要让类实现InotifyPropertyChanged接⼝并在熟悉的set语句中激发PropertyChanged事件。
除了对象作为数据源外,还可以有很多选择,控件⾃⼰或⾃⼰的容器或⼦集元素、集合作为ItemsCont
rol的数据源、XML作为TreeView或Menu的数据源、把多个控件关联到⼀个“数据制⾼点”上、甚⾄⼲脆不给Binding指定数据源,让它⾃⼰去
6.3.1 把控件作为Binding源与Binding标记拓展
⼤多数情况下Binding的源是逻辑层对象,但有时候为了让UI元素产⽣联动效果也会使⽤Binding在控件间建⽴关联。
如把TextBox的Text属性关联在Slider的Value属性上
<StackPanel>
<TextBox x:Name="textBox1" Text="{Binding Path=Value,ElementName=slider1}" BorderBrush="Black" Margin="5"/>
<Slider x:Name="slider1" Maximum="100" Minimum="0" Margin="5"/>
</StackPanel>
<TextBox x:Name="textBox1" Text="{Binding Path=Value,ElementName=slider1}" BorderBrush="Black" Margin="5"/>
与下⾯C#代码等价,且上⾯Path=可以省略
注意:
在C#代码中可以访问XAML代码中声明的变量,但XAML代码中⽆法访问C#代码中声明的变量。
因此,要想在XAML中建⽴UI元素与逻辑层对象的Binding还要颇费些周折,把逻辑层对象声明为XAML代码中的资源(Resource),见资源⼀章。
6.3.2 控制Bangding的⽅向及数据更新
有时候数据只需要展⽰给⽤户、不允许⽤户修改,这时候可以把Binding模式更改为从源向⽬标的单向沟通 (源→⽬标:OneWay)
Mode:属性Mode控制绑定⽅向。BindingMode类型的枚举值:TwoWay、OneWay、OnTime、OneWayToSource和Default。
TwoWay 源↔⽬标 ⽆论是⽬标属性还是源属性,只要发⽣了更改,TwoWay 就会更新⽬标属性或源属性。
OneWay 源→⽬标 仅当源属性发⽣更改时更新⽬标属性。
OneTime 仅当应⽤程序启动时或 进⾏更改时更新⽬标属性。
OneWayToSource ⽬标→源 在⽬标属性更改时更新源属性。
Default 使⽤⽬标属性的默认 值。(这⾥的Default指的是Binding的模式会根据⽬标是实际情况来确定,如果是可以编辑的(TextBox的Text属性),Default就采⽤双向模式。如果是TextBlock,不可编辑,就使⽤单向模式。)
上述Slider⽰例中,在TextBox输⼊⼀个值,然后按Tab键(TextBox丢失焦点),Slider的⼿柄会⾃动跳到相应的位置。
为什么⼀定要丢失焦点后Slider的值才变呢?
UpdateSourceTrigger:属性控制值改变时机。枚举值PropertyChanged、LostFocus、Explicit和Default
Explicit,源不会更新除⾮你⼿动来操作
LostFocus,⼀旦⽬标控件失去焦点,源就会被更新。
PropertyChanged,⼀旦绑定的属性值改变,源会⽴即更新。
View Code
6.3.3 Binding的路径(Path)
即绑定到底需要关注哪个属性的值。前⾯例⼦是把Slider控件当做源,它的Value作为路径
Path属性对应c#的实际类型是PropertyPath
Binding binding = new Binding(){Path=new PropertyPath("Value"),Source=this.slidr1};
Path⽀持多级路径(即⼀路“点”下去)
如 {Binding Path=Text.Length}
如果集合作为源,想把集合中的元素当做Path可以使⽤多级斜杠的⽅式
如 new Binding("/Name") new Binding("/ProvinceList.Name")
6.3.4 没有Path的Binding
有点时候Path是⼀个. 或者⼲脆没有Path
这是⼀种特殊的情况——Binding源本⾝就是数据且不需要Path来指明
如string、int等基本类型,可以将Path设置为".",XAML中.可以省略,C#代码中不可以省
6.3.5 为Binding指定源(Source)的⼏种⽅式
Binding的源是数据的来源,只要⼀个对象包含数据并能通过属性获取到,它就能当作Binding的源 *普通CLR类型对象,只要改对象实现了INotifyPropertyChanged接⼝即可当作源
*普通CLR集合类型对象: 数组、List<T>、ObservableCollection<T>
经常把集合作为ItemsControl派⽣类的数据源
*ADO.NET数据对象:DataTable和DataView等
*XML,使⽤XmlDataProvider
*依赖对象(Dependency Object)
*容器的DataContext (WPF默认使⽤的源)
*ElementName指定源:在C#代码中把对象的Name作为源赋给Binding
*RelativeSource指定源:当控件需要关注⾃⼰的、⾃⼰容器的或者⾃⼰内部元素的某个值时
*ObjectDataProvider:当数据源的数据不是通过属性⽽是通过⽅法暴露给外界时
*LINQ检索得到的数据对象
下⾯通过实例分述每种情况
6.3.6 没有Source的Binding——使⽤DataContext作为Binding的源
所有WPF控件(包括容器控件)都具备DataContext属性
在UI元素树的每个节点都有DataContext
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
<StackPanel Background="LightBlue">
<StackPanel.DataContext>
<local:Student Id="6" Age="29" Name="tim"/>
</StackPanel.DataContext>
<Grid >
<StackPanel>
<TextBox Text="{Binding Path=Id}" Margin="5"/>
<TextBox Text="{Binding Path=Name}" Margin="5"/>
<TextBox Text="{Binding Path=Age}" Margin="5"/>
</StackPanel>
</Grid>
</StackPanel>
UI布局如下
在XAML中为外层StackPanel的DataContext赋了值,内层TextBox的Binding只指定了Path,没有指定Source,这时TextBox的Binding会⾃动向UI元素树的上层寻可⽤的DataContext对象
如果Source本⾝就是数据,Binding的Path可以设置为"."或不写
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<StackPanel Background="LightBlue">
<StackPanel.DataContext>
<sys:String >Hello DataContext!</sys:String>
</StackPanel.DataContext>
<Grid >
<StackPanel>
<TextBlock Text="{Binding}" Margin=" 5"/>
<TextBlock Text="{Binding .}" Margin=" 5"/>
</StackPanel>
</Grid>
</StackPanel>
此处使⽤TextBlock,如果使⽤TextBox提⽰ 双向绑定需要Path或Xpath
其实,“Binding沿着UI元素树⽹上”只是WPF给我们的⼀个错觉,实际是因为DataContext是⼀个“依赖属性”,当控件的依赖属性没有显式赋值时,依赖属性值会沿UI元素树向下传递。
DataContext的⽤法:fontweight属性bold
*当UI上多个控件Binding同⼀个对象时
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论