网络资源-深入剖析Binding2(学习)
WPF Binding
WPF里分三种Binding:Binding, PriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension
Binding:
提供对绑定定义的高级别访问,绑定将绑定目标对象(通常为 WPF 元素)的属性与任何数据源(例如数据库、XML 文件或包含数据的任何对象)连接起来。
常见的使用Binding的代码:
C#
Binding binding = new Binding(); binding.Source = treeView; // Set source object binding.Path = new PropertyPath("SelectedItem.Header"); // Set source property SetBinding(TextBlock.TextProperty, binding); // Attach to target property currentFolder.
所有 FrameworkElement都包含SetBinding方法:SetBinding(DependencyProperty dp, String path), SetBinding(DependencyProperty dp, BindingBase binding),可以看出,FrameworkElement中的SetBinding只对DependencyProperty有效。
另一种设置Binding的方法是:BindingOperations.SetBinding(currentFolder, TextBlock.TextProperty, binding);
BindingOperations.SetBinding的原型是
public static BindingExpressionBase SetBinding( DependencyObject target, DependencyProperty dp, BindingBase binding)
第一个参数是DependencyObject,所以我们可以对自定义DependencyObject或者继承自DependencyObject的类进行绑定。当然第二个参数还是DependencyProperty。
XAML:
<TextBlock x:Name=”currentFolder” DockPanel.Dock=”Top” Text=”{Binding ElementName=treeView, Path=SelectedItem.Header}” Background=”AliceBlue” FontSize=”16”/>
清除Binding:
BindingOperations.ClearBinding(currentFolder, TextBlock.TextProperty); //删除currentFolder上的TextBlock.TextProperty绑定 BindingOperations.ClearAllBindings(currentFolder); //删除currentFolder上的所有绑定
直接对dependency property赋值也可以解除binding, 不过只对单向binding有效。
Bingding的源:
<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
- 源是元素本身的例子:{Binding RelativeSource={RelativeSource Self}}
- 源是Tempalte中元素的Parent:{Binding RelativeSource={RelativeSource TemplatedParent}}
- 源是绑定以collection形式的前一个数据:{Binding RelativeSource={RelativeSource PreviousData}},MSDN上关于PreviousData的说明并不多,这里有一篇文章可以参考
- 源是Ancestor(可能比parent还高):{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=n, AncestorType={x:Type desiredType}}}
<Window x:Class="Yingbao.Chapter2.RelativeEx.AppWin" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="相对绑定" Height="100" Width="300"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <TextBlock FontSize="20" Text="{Binding RelativeSource={RelativeSource self}, Path=FontSize}"/> <TextBlock Margin="10,1,1,5" FontSize="20" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Path=Orientation}"/> </StackPanel> </Window>
在这个例子中,使用了两个相对数据源扩展,第一个TextBlock的Text绑定到自身的字体大小上;第二个TextBlock的Text则绑定到其父节点StackPanel的Orientation属性上。这段XAML的运行结果如图2-5所示。
Path:
1:Binding中的Path是PropertyPath对象。在最简单的情况下,Path制定一个源的属性,如 Path=PropertyName。
2:通过类似于 C# 中使用的语法,可以指定子属性。例如,子句 Path=ShoppingCart.Order 将绑定设置为对象的子属性 Order。
3:若要绑定到附加属性,请将附加属性用括号括起。例如,若要绑定到附加属性 DockPanel.Dock,则语法为 Path=(DockPanel.Dock)。
4:在应用了索引器的属性名称之后的方括号内,可以指定属性的索引器。例如,子句 Path=ShoppingCart[0] 将绑定设置为与属性的内部索引处理文本字符串“0”的方式对应的索引。此外,还支持多个索引器。在 Path 子句中可以同时使用索引器和子属性,例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street]。在索引器内部,可以有多个由逗号 (,) 分隔的索引器参数。可以使用圆括号指定每个参数的类型。例如,可以使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空间。
5:如果源为集合视图,则可以用斜杠 (/) 指定当前项。例如,子句 Path=/ 设置到视图中当前项的绑定。如果源为集合,则此语法指定默认集合视图的当前项。
6:可以结合使用属性名和斜杠来遍历作为集合的属性。例如,Path=/Offices/ManagerName 指定源集合的当前项,该源集合包含同样是集合的 Offices 属性。其当前项是包含 ManagerName 属性的对象。
7:也可以使用句点 (.)路径绑定到当前源。例如,Text=”{Binding}” 等效于 Text=”{Binding Path=.}”。
BindingExpression
Binding 类是高级别类。BindingExpression 类是基础对象,用于保持绑定源与绑定目标之间的连接。Binding 中包含可在多个 BindingExpression 对象之间共享的所有信息。也就是说,可以把一个Binding对象绑定对n个元素上,而针对这n个元素,分别有相应的n个BindingExpresion对象。
Binding 可以直接绑定普通的.net实例,比如int值。但是如果后台改变int值了,前台不能显示改变后的值,这时可以调用UpdateTarget()方法更 新绑定。如下:
BindingExpression be = button.GetBindingExpression(Button.ContentProperty); be.UpdateTarget();
还有UpdateSource方法用来更新源。
绑定到.net属性/对象:
上面提到Binding绑到普通的.net属性,如果source变化了,UI上是不会显示的,除了用BindingExpression每次显式更新Target外,还可以使用如下技术:绑定到单个对象需实现INotifyPropertyChanged接口,这个接口只有一个成员:
event PropertyChangedEventHandler PropertyChanged
实现INotifyPropertyChanged的示例如下:
using System.ComponentModel; namespace SDKSample { // This class implements INotifyPropertyChanged // to support one-way and two-way bindings // (such that the UI element updates when the source // has been changed dynamically) public class Person : INotifyPropertyChanged { private string name; // Declare the event public event PropertyChangedEventHandler PropertyChanged; public Person() { } public Person(string value) { this.name = value; } public string PersonName { get { return name; } set { name = value; // Call OnPropertyChanged whenever the property is updated OnPropertyChanged("PersonName"); } } // Create the OnPropertyChanged method to raise the event protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } } } 或者显式实现INotifyPropertyChanged:
#region INotifyPropertyChanged Members event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add { this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value); } remove { this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value); } } #endregion
看了上面代码着实没看出source值改变了,前台是通过什么机制反映的,正常的情况下公开了一个事件,必须有一个对此事件的实现体,而上面代码并没有实现PropertyChanged的方法。
我猜想是Binding内部获取了这个接口并对PropertyChanged进行了赋值,因为在debug时,这个事件确实被赋值的,而赋值前的Stack是External Code调用的。
绑定到集合需实现INotifyCollectionChanged,但是推荐使用ObservableCollection<T>,这个类实现了INotifyCollectionChanged和INotifyPropertyChanged。
附:当绑定到普通的.net属性时,WPF使用反射取得source的值,当对象实现ICustomTypeDescriptor时,WPF使用这个接口取得值,性能上会有所提升。
DataContext:
DataContext在共享资源时最有用。
<StackPanel x:Name="parent" DataContext="{StaticResource photos}"> <Label x:Name="numItemsLabel" Content="{Binding Path=Count}" DockPanel.Dock="Bottom"/>等价C#中代码是:parent.DataContext = photos;
Value Converters: IValueConverter可以在绑定时加入自己的逻辑,很好。
public class RawCountToDescriptionConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { int num = int.Parse(value.ToString()); // Let Parse throw an exception if the input is bad return num + (num == 1 ? " item" : " items"); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
IValueConverter就两个方法需要自己实现,Convert和ConvertBack,一个转过来,一个转过去。 XAML代码使用converter
<Window.Resources> <local:CountToBackgroundConverter x:Key="myConverter"/> </Window.Resources>...... <Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, Source={StaticResource photos}}"/>
这里的myConverter是个resource,需要在xaml中预先定义:
Count值会作为第一个参数value传给Convert方法。
注意,返回的值一定要是绑定时对应的值,比如绑定时需要绑到Geometry类上,那么Convert返回的也必须是Geometry类。
Convert方法还带有一个parameter参数,可以在xaml中这么使用,这样C#代码中就可以得到parameter的值了。
<Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, ConverterParameter=Yellow, Source={StaticResource photos}}"/>
ConverterParameter是object类型。
TIP:
可以用Binding.DoNothing作返回值,以指示绑定引擎不要执行任何操作。
可 用使用[ValueConversion(typeof(DateTime), typeof(String))]来标识Converter要转化和返回的值类型,第一个参数是soure,第二个参数是target。这样在编译时,如 果类型不匹配的话,编译器会抛出异常:error CS0592: Attribute 'ValueConversion' is not valid on this declaration type. It is only valid on 'class' declarations.
.net自带一些converter,比如常用的BooleanToVisibilityConverter,可以根据checkbox是否勾上来隐藏其他控件。
常见的使用位置:
- 在collection中使用converter
- 使用DateTemplate,在其中使用Converter
- 也可以使用Converter对整个collection进行转化,但是可能效率不好
Binding.Mode
指示源和目标间数据流的方向。
- OneWay 源更新时,目标也更新
- TwoWay 源更新时目标也更新,或者目标更新时同时更新源
- OneTime 仅当应用程序启动时或 DataContext 进行更改时更新目标属性。绑一次就不更维护更新,目标相当于源的一次性镜像
- OneWayToSource 目标更新时更新源,和OneWay相反。OneWayToSource 用于多个目标更改一个源的情况,可以想像成多人录入。或者用来实现源和目标倒置的情况。
大部分WPF自带的控件的dependency property默认的是OneWay,像TextBox.Text默认的是TwoWay。
值得注意的事,只读属性只能设置成OneWay,不能是TwoWay,否则运行时异常。
注意:再次提醒,源要实现INotifyPropertyChanged 接口才能传到目标。
- 对于 OneWay 或 TwoWay 绑定,对源的动态更改不会自动传播到目标。必须在源对象上实现 INotifyPropertyChanged 接口。
- 对于 TwoWay 绑定,对目标的更改不会自动传播到源,除非绑定目标是 Text 属性。在这种情况下,更新仅在 TextBox 失去焦点时发生。
- 对于 OneTime 和 OneWay 绑定,对 SetValue 的调用会自动更改目标值并删除绑定。
Binding实例: http冒号//www点wpf123点com/news/?8849.html
![](/assets/blank.gif)
![](/assets/blank.gif)
1 <Window x:Class="Binding2.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="350" Width="525"> 5 6 <Window.Resources> 7 <DataTemplate x:Key="nameDT"> 8 <TextBlock x:Name="textBoxName" Text="{Binding Name}"/> 9 </DataTemplate> 10 11 <DataTemplate x:Key="skillDT"> 12 <TextBlock x:Name="textBoxSkill" Text="{Binding Skill}"/> 13 </DataTemplate> 14 15 <DataTemplate x:Key="hmDT"> 16 <CheckBox x:Name="checkBoxJob" IsChecked="{Binding HasM}"/> 17 </DataTemplate> 18 19 </Window.Resources> 20 <Grid Margin="5"> 21 <Grid.RowDefinitions> 22 <RowDefinition Height="3*"/> 23 <RowDefinition Height="1*"/> 24 </Grid.RowDefinitions> 25 <ListView x:Name="listViewHeros" Grid.Row="0"> 26 <ListView.View> 27 <GridView> 28 <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}"/> 29 <GridViewColumn Header="姓名" CellTemplate="{StaticResource nameDT}"/> 30 <GridViewColumn Header="能力" CellTemplate="{StaticResource skillDT}"/> 31 <GridViewColumn Header="已婚" CellTemplate="{StaticResource hmDT}"/> 32 33 </GridView> 34 </ListView.View> 35 </ListView> 36 <Button Grid.Row="1" Content="给关老爷正名!" Click="Button_Click"/> 37 </Grid> 38 </Window>
![](/assets/blank.gif)
![](/assets/blank.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Data; 8 using System.Windows.Documents; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 using System.ComponentModel; 15 16 namespace Binding2 17 { 18 /// <summary> 19 /// Interaction logic for MainWindow.xaml 20 /// </summary> 21 public partial class MainWindow : Window 22 { 23 24 public class Hero : INotifyPropertyChanged 25 { 26 public event PropertyChangedEventHandler PropertyChanged; 27 28 private string skill; 29 private string name; 30 31 public int Id { get; set; } 32 public string Name 33 { 34 get { return name; } 35 set 36 { 37 name = value; 38 if (PropertyChanged != null) 39 { 40 PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); 41 } 42 } 43 } 44 public bool HasM { get; set; } 45 public string Skill 46 { 47 get { return skill; } 48 set 49 { 50 skill = value; 51 if (PropertyChanged != null) 52 { 53 PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Skill")); 54 } 55 } 56 } 57 58 59 public Hero(int id, string name, string skill, bool hasM) 60 { 61 this.Id = id; 62 this.Name = name; 63 this.Skill = skill; 64 this.HasM = hasM; 65 } 66 } 67 68 Dictionary<string, Hero> map = new Dictionary<string, Hero>(); 69 70 private void InitDictionary() 71 { 72 Hero hero1 = new Hero(1, "刘备", "哭泣", true); 73 map.Add(hero1.Name, hero1); 74 Hero hero2 = new Hero(2, "官羽", "贪污", false); 75 map.Add(hero2.Name, hero2); 76 Hero hero3 = new Hero(3, "黄忠", "射击", true); 77 map.Add(hero3.Name, hero3); 78 Hero hero4 = new Hero(4, "魏延", "突击", true); 79 map.Add(hero4.Name, hero4); 80 Hero hero5 = new Hero(5, "马超", "单挑", false); 81 map.Add(hero5.Name, hero5); 82 Hero hero6 = new Hero(6, "曹仁", "防守", true); 83 map.Add(hero6.Name, hero6); 84 } 85 public MainWindow() 86 { 87 InitializeComponent(); 88 InitDictionary(); 89 90 Binding binding = new Binding(); 91 binding.Source = map; 92 binding.Path = new PropertyPath("Values"); 93 listViewHeros.SetBinding(ListView.ItemsSourceProperty, binding); 94 95 //listViewHeros.ItemsSource = map.Values; //可以使用这行来代替上面的binding 90~93 96 } 97 98 private void Button_Click(object sender, RoutedEventArgs e) 99 { 100 map["官羽"].Name = "关羽"; 101 map["官羽"].Skill = "单挑"; 102 } 103 104 105 } 106 }
转载于:https://www.cnblogs.com/shawnzxx/archive/2012/11/10/2763544.html
网络资源-深入剖析Binding2(学习)相关推荐
- 《STL源码剖析》学习--6章--_rotate算法分析
最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. <STL源码剖析>学习--6章--random access ite ...
- 剖析强化学习 - 第三部分
作者:Massimiliano Patacchiola 欢迎来到"剖析强化学习"系列的第三部分.在第一篇和第二篇文章中,我们分析了动态规划和蒙特卡罗(MC)方法.第三部分要讲的强化 ...
- 从这篇YouTube论文,剖析强化学习在工业级场景推荐系统中的应用
作者 | 吴海波 转载自知乎用户吴海波 [导读]本文作者根据两篇工业界背景的论文解答了 RL 在推荐场景需要解决的问题与困难,以及入门需要学习得相关知识点. 2 个月前,业界开始流传 youtube ...
- 《STL源码剖析》学习-- 1.9-- 可能令你困惑的C++语法1
最近在看侯捷的<STL源码剖析>,虽然感觉自己c++看得比较深一点,还是感觉还多东西不是那么明白,这里将一些细小的东西或者概念记录一下. 有些东西是根据<C++编程思想>理解的 ...
- 《STL源码剖析》学习--6章--power算法分析
最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. 6章--power算法分析 书本中的算法如下所示: template <clas ...
- 《C语言深度剖析》学习笔记----C语言中的符号
本节主要讲C语言中的各种符号,包括注释符.单引号双信号以及逻辑运算符等. 一.注释符 注释符号和注释在程序的预编译期就已经被解决了,在预编译期间,编译器会将注释符号和注释符号之间的部分简单的替换成为空 ...
- 剖析强化学习 - 第八部分
作者:Massimiliano Patacchiola 在上一篇文章中,我介绍了函数逼近作为在强化学习设置中表示效用函数的方法.我们使用的简单逼近器基于特征的线性组合,并且它非常有限,因为它无法模拟复 ...
- 【开源项目学习】源码剖析,学习仿网易云音乐app代码
[前言] 这篇文字不全是讲app代码,而是博主怎么根据代码系统学习梳理的过程,非专业,如有不对,欢迎指出 仿网易云音乐app源码地址:https://github.com/aa112901/remus ...
- 深度剖析集成学习GBDT
GBDT 2 GBDT 2.0 参数概述和迭代过程 特点 参数概述 迭代过程 2.1 init 2.1.1 model 2.1.2 zero 2.1.3 None(sklearn默认) 2.1.4 测 ...
最新文章
- 【项目管理】Project使用
- 关于MyEclipse连接SQLServer和Mariadbsql
- android 学习随笔二十(多媒体编程 )
- JS中 window.location.search的作用
- yolo-tensorrt 运行 make报错 error: ‘int nvinfer1::MishPlugin marked ‘override’, but does not override
- Linux之ssh-copy-id命令
- 基于DEAP库的python进化算法-4.遗传算法求解TSP问题
- 86五笔输入法教程详解
- 2018年华北五省计算机应用大赛参赛作品--战拖儿app
- 《工程电磁场(第三版)》(倪光正 主编)复习
- 谈:典型三种近场通信的特点以及未来趋势
- android学习笔记-连接新大陆物联网云平台控制stm32
- 以“数”防疫,快速实施,两周落地,天翎疫情管理系统
- 硬盘不能进PE的问题与解决
- IC验证笔试题(寒武纪)
- 一个队长应该干什么?
- oracle nvl和nvl2的区别
- 【值得收藏】一份非常完整的Mysql规范
- 没时间学 Vue (7) —— 渲染(二):条件渲染 v-if
- 分享一个有趣的斯特林发动机