WPF学习(二) - 绑定
绑定,这个看起来很神奇的东西,于我这种喜欢刨根儿的人而言,理解起来非常困难。
WPF绑定的核心思想是:数据层属性值的改变,能反应给展示层,反之亦然,并且这个响应的过程能被分离出来。
传统Winform编程更加原始,没有那么多隐藏的(implicate)技术。我就以winform的实现方式来领会WPF的机制。
public class DataLayer
{
public delegate void TextChangedEventHandler ( object sender, EventArgs e ); public event TextChangedEventHandler TextChanged; private string text = ""; public string Text
{
get { return text; }
set
{
if ( text != value )
{
text = value;
if ( this.TextChanged != null )
this.TextChanged ( this, new EventArgs ( ) );
}
}
} }
数据层代码
public partial class PresentationLayer : Form
{
TextBox ui = new TextBox ( );
DataLayer data = new DataLayer ( ); public PresentationLayer ( )
{
InitializeComponent ( );
this.Controls.Add ( ui ); ui.TextChanged += new System.EventHandler ( this.PresentationLayerTextChanged );
data.TextChanged += new DataLayer.TextChangedEventHandler ( this.DataLayerTextChanged );
} private void PresentationLayerTextChanged ( object sender, EventArgs e )
{
data.Text = ui.Text;
} private void DataLayerTextChanged ( object sender, EventArgs e )
{
ui.Text = data.Text;
} }
展示层代码
这样就实现了前、后台数据的同步。缺点有三方面:
1、每个属性的数据同步,功能单一,内容相同。没有必要在数据层对每个属性的响应事件都单独定义事件委托。
2、为了保持数据同步,需要在展示层编写大量的数据同步代码。如果有很多个属性,重复的工作量非常大。
3、data作为PresentationLayer的成员,增加了耦合度。数据层和展示层没有完全分隔开。
问题1很好解决,从数据层抽象出一个接口事件,并在事件参数中要求说明激发事件的属性名
public interface INotifyPropertyChanged
{
event PropertyChangedEventHandler PropertyChanged;
} public delegate void PropertyChangedEventHandler ( object sender, PropertyChangedEventArgs e ); public class PropertyChangedEventArgs : EventArgs
{
private readonly string propertyName; public PropertyChangedEventArgs ( string propertyName )
{
this.propertyName = propertyName;
} public virtual string PropertyName
{
get
{
return this.propertyName;
}
}
}
抽象出来的接口事件
这样,原始的DataLayer就变成这样
public class DataLayerExt : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; private string text = ""; public string Text
{
get { return text; }
set
{
if ( text != value )
{
text = value;
if ( this.PropertyChanged != null )
this.PropertyChanged ( this, new PropertyChangedEventArgs ( "Text" ) );
}
}
} }
DataLayerExt
问题2从逻辑上也不难解决,定义一个静态的方法,方法的参数要说明是哪两个对象的哪两个属性需要同步,并记录这种同步关系
public class BindingOperations
{
static List<BindingRelative> lstBindingRelative = new List<BindingRelative>(); // 源和目标的类型应该是object。这里只为表达语意,完全实现很困难
public static void SetBinding ( TextBox uiObject, string uiPropertyName, DataLayerExt dataObject, string dataPropertyName )
{
// 用列表记录同步关系
lstBindingRelative.Add ( new BindingRelative ( ) { UIObject = uiObject, UIObjectPropertyName = uiPropertyName, DataObject = dataObject, DataObjectPropertyName = dataPropertyName } );
// 增加事件处理方法
uiObject.TextChanged += new EventHandler ( uiObject_TextChanged );
dataObject.PropertyChanged += new PropertyChangedEventHandler ( target_PropertyChanged );
} static void uiObject_TextChanged ( object sender, EventArgs e )
{
foreach ( BindingRelative item in lstBindingRelative )
{
if ( item.UIObjectPropertyName == "Text" )
{
// 通用的方式应该是这样
//item.Source.SourcePropertyName = item.Target.dataPropertyName;
item.DataObject.Text = item.UIObject.Text;
break;
}
}
} static void target_PropertyChanged ( object sender, PropertyChangedEventArgs e )
{
foreach ( BindingRelative item in lstBindingRelative )
{
if ( item.DataObjectPropertyName == e.PropertyName )
{
// 通用的方式应该是这样
//item.Source.SourcePropertyName = item.Target.dataPropertyName;
item.UIObject.Text = item.DataObject.Text;
break;
}
} }
} //定义一个用来记录绑定关系的结构
public class BindingRelative
{
public TextBox UIObject;
public string UIObjectPropertyName;
public DataLayerExt DataObject;
public string DataObjectPropertyName;
}
建立数据同步关系
这样,展示层只需要设计界面的风格,定义界面中的展示元素,与后台数据完全分离。不知不觉中,问题1也一并解决了。
public partial class PresentationLayerExt : Form
{ public TextBox ui = new TextBox ( ); public PresentationLayerExt ( )
{
InitializeComponent ( );
this.Controls.Add ( ui );
} }
PresentationLayerExt
当然,指定同步关系还是要用代码实现的,但不在展示层,而是在外部,比如在Main()函数处
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main ( )
{
Application.EnableVisualStyles ( );
Application.SetCompatibleTextRenderingDefault ( false ); PresentationLayerExt p = new PresentationLayerExt ( );
DataLayerExt d = new DataLayerExt ( );
BindingOperations.SetBinding ( p.ui, "Text", d, "Text" ); Application.Run ( p );
}
}
Main()
以上,用Winform实现了数据同步,并做到了数据层与展示层的分离。由于Winform中根据属性名称字符串获取对象的属性非常困难,定义同步关系的方法SetBinding有很大的缺陷,几乎没有通用性可言。但这不妨碍通过Winform的示例理解WPF绑定技术的运行机制。
WPF的绑定技术,实现数据层和展示层的数据同步原理也是这样:
数据层的类需要派生自System.ComponentModel中的INotifyPropertyChanged接口,
每个类都必须包含PropertyChanged事件,并在属性值改变时,激发这个事件,事件参数中传入属性名。
数据同步关系由BindingOperations的SetBinding方法建立。
在WPF中SetBinding方法的后两个参数打包成Binding类型的对象
这样,SetBinding方法的对象参数就可以使用最原始的DependencyObject类型的对象,提高通用性。
很多WPF控件已封装过SetBinding方法,这样就在对象绑定自己的属性时,就可以调用自己的SetBinding方法省略目标这个参数
一个完整的WPF应用Binding技术的例子
// Data作为绑定的数据源头,总会接收绑定目标的改变
// 但是,如果想将Data源头的改变告诉绑定目标,
// 必须要从INotifyPropertyChanged接口派生,并实现响应事件的激发
public class DataClass : System.ComponentModel.INotifyPropertyChanged
{
private string myString; public string MyString
{
get { return myString; }
set
{
myString = value; //激发事件
if ( PropertyChanged != null )
PropertyChanged ( this, new System.ComponentModel.PropertyChangedEventArgs ( "MyString" ) );
}
} public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; }
定义数据类
// 作为被绑定的目标类,必须从DependencyObject派生
// 这样定义的类才能满足SetBinding方法的第一个参数的类型要求
// 还要额外定义一个依赖属性,用来满足SetBinding方法的第二个参数要求
// 用DependencyObject派生方法GetValue和SetValue,控制属性的存、取
public class UIClass : System.Windows.DependencyObject
{
public string MyText
{
get { return ( string ) GetValue ( MyTextProperty ); }
set { SetValue ( MyTextProperty, value ); }
} public static readonly System.Windows.DependencyProperty MyTextProperty =
System.Windows.DependencyProperty.Register ( "MyText", typeof ( string ), typeof ( UIClass ) ); }
展示类
测试类
相比Winform,WPF实现了按属性名称存/取对象属性的功能,并把这个技术叫做依赖属性。
有了依赖属性,WPF的SetBinding方法就真正做到通用,这个技术在后面继续研究。
程序的世界哪有什么神奇,只是有的人做了更多的工作,结果看起来很神奇而已。
所谓的数据与展示分离,不过是在这两层之外,额外创建了一个管理机构。
而WPF的绑定技术,就是这个管理机构中的一个部门,负责收、发快递!
WPF学习(二) - 绑定的更多相关文章
- WPF学习:绑定
原文 http://www.cnblogs.com/SouthAurora/archive/2010/06/30/1768464.html 一.绑定到元素对象 1.元素和元素(XAML.代码) 1.1 ...
- WPF学习二:TextBlock和Label的区别
TextBlock和Label都是用来显示少量数据的.好多文章对Label存在的描述都是它允许使用"快速获取"."快速获取"就是允许你用Alt加上其它的按键快速 ...
- 【WPF学习】第二十九章 元素绑定——将元素绑定到一起
数据banding的最简单情形是,源对象时WPF元素而且源属性是依赖性属性.前面章节解释过,依赖项属性具有内置的更改通知支持.因此,当在源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性.这 ...
- WPF学习拾遗(二)TextBlock换行
原文:WPF学习拾遗(二)TextBlock换行 下午在帮组里的同事解决一个小问题,为了以后方便,把就把它收集一下吧. 新建一个TextBlock作为最基础的一个控件,他所携带的功能相对于其他的控件要 ...
- WPF学习之路初识
WPF学习之路初识 WPF 介绍 .NET Framework 4 .NET Framework 3.5 .NET Framework 3.0 Windows Presentation Found ...
- 【WPF学习】第五十三章 动画类型回顾
创建动画面临的第一个挑战是为动画选择正确的属性.期望的结果(例如,在窗口中移动元素)与需要使用的属性(在这种情况下是Canvas.Left和Canvas.Top属性)之间的关系并不总是很直观.下面是一 ...
- emberjs学习二(ember-data和localstorage_adapter)
emberjs学习二(ember-data和localstorage_adapter) 准备工作 首先我们加入ember-data和ember-localstorage-adapter两个依赖项,使用 ...
- WPF学习开发客户端软件-任务助手(下 2015年2月4日代码更新)
时光如梭,距离第一次写的 WPF学习开发客户端软件-任务助手(已上传源码) 已有三个多月,期间我断断续续地对该项目做了优化.完善等等工作,现在重新向大家介绍一下,希望各位可以使用,本软件以实用性为主 ...
- ReactJS入门学习二
ReactJS入门学习二 阅读目录 React的背景和基本原理 理解React.render() 什么是JSX? 为什么要使用JSX? JSX的语法 如何在JSX中如何使用事件 如何在JSX中如何使用 ...
- WPF学习之资源-Resources
WPF学习之资源-Resources WPF通过资源来保存一些可以被重复利用的样式,对象定义以及一些传统的资源如二进制数据,图片等等,而在其支持上也更能体现出这些资源定义的优越性.比如通过Resour ...
随机推荐
- idea设置Template
在eclipse里面经常会用到syso和main类似这样的内容,但是idea工具里面没有,可以通过 Editor ==> Live templates ==> 1.首先创建一个自己的Te ...
- P1903 【模板】分块/带修改莫队(数颜色)
题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2 ...
- Codeforces 993A. Two Squares(暴力求解)
解题思路(暴力解法) 平行于x轴的正方形和与x轴成45度倾斜的正方形相交的点中必定有整数点.即若两正方形相交,必定存在整数i,j,使(i,j)同时属于两个正方形. 我们把两个正方形中的整数点都找出来, ...
- depth peeling实现半透明
aaarticlea/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aH
- 50个技巧提高你的PHP网站程序执行效率
1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP手册中说echo是语言结构,不是真正的函数,故 把函数加上了双引号). 2.如果能将类的方法定义成static,就尽量定义成static ...
- Guitar Pro 的双十一特惠活动,正在如火如荼进行中...
11月11日这个令人兴奋的日子又来了.没错,“双十一”所有网购达人狂欢的日子.同时期待已久的Guitar Pro 也将在“双十一”当天,把福利分享与你我.11月11日Guitar Pro 将在麦软商城 ...
- 什么是2.5D与3D编辑模式
ZBrush®其实就是一个带有三维特性的二维软件,它不仅具有绘制二维图像的功能,而且也具有对三维物体进行编辑的功能,就是所谓的2.5D(Pixol技术). 学习ZBrush之前有必要了解一下2.5D的 ...
- vue 移动端项目,动态控制div距离底部的距离
<template> <div class="details"> <com-nav-bar title="保险详情"> &l ...
- CentOS 7 安装配置MySQL
环境 CentOS Linux release 7.5.1804 (Core) MySQL:mysql80-community-release-el7-1 检查: 在centos7中默认的是maria ...
- POJ 2187 Beauty Contest( 凸包求最远点对 )
链接:传送门 题意:给出 n 个点,求出这 n 个点中最远的两个点距离的平方 思路:最远点对一定会在凸包的顶点上,然后直接暴力找一下凸包顶点中距离最远的两个点 /******************* ...