绑定(binding)元素介绍
首先,盗用张图。这图形象的说明了binding的机理。
此处主要介绍的绑定类是system.windows.data.binding,如果涉及其他内容,将简要介绍,不会过多说明。
下面将简要介绍最基础(最常用)的三个属性:
1、path —— 路径,用于索引到具体的属性,常常会省略书写,示例如下:
1
|
<textbox text= "{binding path=a.b}" />
|
其中path=可以省略,因为binding元素含有一个带参构造函数,其参数为path。另外,示例中a.b需具体到属性,如果a已经是需要绑定的具体属性,则可以用a替换a.b。即最简单的格式是:
1
|
<textbox text= "{binding a}" />
|
2、mode —— 模式,用于指定数据的更新方向,它是一个枚举类型,共有一下四种方式:
- onetime —— 一次性更新(只更新一次),从数据源更新到当前使用的绑定属性。
- oneway —— 单向更新,从数据源更新到当前使用的属性。
- onewaytosource —— 单向更新,从当前使用的属性更新到数据源。
- twoway —— 双向更新,当前属性与数据源同步。
注:如果未指定,即表示使用默认模式,而在不同的依赖属性上,其模式是不一样的。在使用时,如果不确定其默认模式是否是自己需要的模式时,则可以手动指定。
3、updatesourcetrigger —— 数据源更新触发器,用于指定控件上的属性值什么时候更新到数据源,它也是个枚举类型,有以下三种方式:
- explicit —— 显示更新,需要调用updatesource方法后才能更新。
- lostfocus —— 失去焦点更新
- propertychanged —— 属性值改变更新,大部分情况会使用此方式,但有时频繁的更新数据源会降低效率,如在textbox中,如果数据源有较多的数据验证,此时在输入text时,就有可能出现界面卡顿的情况。
注:当然,此处也有默认值设置,但不同的控件 属性的 默认 值也不一样,不过大部分情况下默认 值是propertychanged,比较特殊的有textbox的text属性,其默认值是lostfocus。
下面给一个最常用的绑定书写方式:
1
|
<textbox text= "{binding a,updatesourcetrigger=propertychanged,mode=twoway}" />
|
控件绑定
控件绑定,即在同一个界面中不同控件之间的数据同步处理,最常见的就是滑动条与一个文本框之间的绑定。在控件绑定中,需要指定绑定类的elementname属性值,即当前属性绑定到哪一个控件的属性上。示例如下:
1
2
|
<slider name= "slider" maximum= "100" />
<textbox text= "{binding elementname=slider,path=value,updatesourcetrigger=propertychanged,mode=twoway}" />
|
注:在wpf开发中,我们常常是不为控件设置name值的,而在控件绑定中,必须为源控件添加name属性值;而有些控件可能会不含有name属性,此时则使用x:name来指定名称。
在控件绑定中有一个比较特殊的存在——模板绑定-templatebinding,它与binding并不在一个继承结构上。templatebinding是用在控件模板定义中的,用于绑定模板对应控件中的属性,示例如下:
1
2
3
4
5
6
7
|
<textbox x:name= "templatebinding" >
<textbox.template>
<controltemplate targettype= "textbox" >
<textblock text= "{templatebinding text}" />
</controltemplate>
</textbox.template>
</textbox>
|
templatebinding可以简单理解为在binding中设置了elementname为其父级控件 —— 事实并非如此,仅作为辅助理解。templatebinding相对与binding要少很多属性内容。
数据绑定
此处数据绑定表示在wpf中的对象绑定,即常见场景 就是把数据库 数据显示到 界面上。而在真实的项目开发中 ,常 会用到mvvm模式,数据绑定将会在那里体现出来,但mvvm模式开发则不在此节中叙述。
下面以一个最简单的示例解释数据绑定:
后台类 —— 数据源结构:
1
2
3
4
|
class fordatabinding
{
public int count { get ; set ; }
}
|
数据源初始化 —— 创建数据并将数据绑定到界面:
1
2
3
|
fordatabinding data = new fordatabinding();
data.count = 10;
this .fordatabinding.datacontext = data;
|
界面控件设置 —— 指定控件绑定到源数据的哪个属性:
1
2
3
|
<grid x:name= "fordatabinding" >
<textbox text= "{binding count}" />
</grid>
|
其中设置了grid的datacontext,即表示grid内部数据上下文是以设置的数据源为基础,在此示例中,text属性绑定的count就是以fordatabinding类对象为基础查找属性。 —— 即绑定路径是以当前位置以树形结构往下查找对应属性。
其他元素
binding除了以上内容,还有其他的属性设置,本小节将简要介绍几个较为常用的内容。
数据格式化转换
在数据绑定中,有时我们需要显示的数据与源数据不一样,如时间格式,浮点数格式,或者更复杂一些的想要一个类对象中的多个属性组合一起显示。
对于简单的数据格式化,可以通过stringformat来处理,如时间格式化为yyyy-mm-dd,浮点数保留两位小数等等。其代码示例如下:
后台类:
1
2
3
4
5
|
class simpledataconvert
{
public datetime date { get ; set ; } = datetime.now;
public float price { get ; set ; } = 100.123456f;
}
|
使用:
1
|
this .simpleconvert.datacontext = new simpledataconvert();
|
界面处理:
1
2
3
4
|
<stackpanel x:name= "simpleconvert" >
<textbox text= "{binding date,stringformat=yyyy-mm/dd}" />
<textblock text= "{binding price,stringformat=f2}" />
</stackpanel>
|
上述示例结果就是将date日期格式化为yyyy-mm/dd;将price保留两位小数显示。
但是有些数据显示要求无法通过stringformat处理,则需要使用binding的属性converter来处理了 —— 即通过值转换器来处理。下面我们以上面用到的时间转化为例,假如我们要在前台显示yyyymmdd格式的日期,此时从数据源显示到界面可以正确处理,但是在界面输入,它无法正确转化为源数据,即内置的converter不支持,此时我们就需要自己实现值转换,示例 如下:
首先定义dateconverter,实现接口ivalueconverter,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
class dateconverter : ivalueconverter
{
/// <summary>
/// 数据源转界面显示
/// </summary>
/// <param name="value"></param>
/// <param name="targettype"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object convert( object value, type targettype, object parameter, cultureinfo culture)
{
if (value.gettype() == typeof (system.datetime))
{
return ((system.datetime)value).tostring( "yyyymmdd" );
}
else
{
return value;
}
}
/// <summary>
/// 界面显示转数据源
/// </summary>
/// <param name="value"></param>
/// <param name="targettype"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object convertback( object value, type targettype, object parameter, cultureinfo culture)
{
if (targettype == typeof (system.datetime) && value != null )
{
datetime dt = datetime.now;
string valuestr = value.tostring();
if (datetime.tryparse(valuestr, out dt))
{
return dt;
}
else if (valuestr.length == 8)
{
string yearstr = valuestr.substring(0, 4);
string monthstr = valuestr.substring(4, 2);
string daystr = valuestr.substring(6, 2);
if (datetime.tryparse( string .format( "{0}-{1}-{2}" , yearstr, monthstr, daystr), out dt))
{
return dt;
}
}
}
return value;
}
}
|
然后在xaml文件中添加引用:
由于此处dateconvert直接定义在当前窗体类命名空间下,所以其已经默认添加了如下空间,如果定义在其他位置,则需要手动添加空间引用。
1
|
xmlns:local= "clr-namespace:binding_demo"
|
资源定义,以便于在控件中引用
1
2
3
|
<window.resources>
<local:dateconverter x:key= "dateconvert" />
</window.resources>
|
最后,则将值转换器应用到控件上,代码如下:
1
|
<textbox text= "{binding date,converter={staticresource dateconvert}}" />
|
至此,一个简单的值转换器就完成了。
数据验证
在绑定中的验证主要设计四个属性:
- validatesondataerrors或者validatesonnotifydataerrors(wpf 4.5之后才有的)—— 与dataerrorvalidationrule或notifydataerrorvalidationrule组合使用
- validatesonexceptions —— 与exceptionvalidationrule组合使用
- notifyonvalidationerror —— 控制是否触发validation.error事件,用于额外的内容处理
- validationrules —— 验证规则,用于定义验证规则集合
下面我们以异常验证规则来简要介绍验证规则的使用 —— 验证处理涉及的内容有很多,单此一节无法描述完整,故仅列举最简单的使用方式:
首先是后台类的定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class forexceptionvalidate
{
private int max;
public int max
{
get { return max; }
set
{
if (value > 100)
{
throw new exception( "max不能超过100" );
}
max = value;
}
}
}
this .forvalidate.datacontext = new forexceptionvalidate();
|
然后是界面使用:
1
2
3
4
5
6
7
8
9
10
11
|
<stackpanel x:name= "forvalidate" >
<textbox >
<textbox.text>
<binding path= "max" >
<binding.validationrules>
<exceptionvalidationrule></exceptionvalidationrule>
</binding.validationrules>
</binding>
</textbox.text>
</textbox>
</stackpanel>
|
在此 示例 中,后台类中抛出的异常,会作为界面的验证结果来处理 —— 所以此处虽然没有明确使用异常捕获,但程序并 不会崩溃。
依赖属性
最后,简要说下依赖属性,所有上面的绑定基础都需要靠依赖属性。所有需要绑定功能的属性都进行了对应依赖属性(system.windows.dependencyproperty)定义。在wpf中,我们大部分时间是在用依赖属性 —— 各种绑定,而自己的定义依赖属性的情况相对较少,所以此处就不再介绍如何定义依赖属性 —— 作为入门介绍教程。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://www.shisujie.com/blog/Binding