前言
在数据绑定过程中,我们经常会使用stringformat
对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如 button
的 content
属性以及tooltip
属性绑定数据进行stringformat
时是无效的。
首先回顾一下stringformat
的基本用法。
stringformat的用法
stringformat
是 bindingbase
的属性,指定如果绑定值显示为字符串,应如何设置该绑定的格式。
因此,bindingbase
的三个子类:binding
、multibinding
、prioritybinding
都可以对绑定数据进行格式化。
binding
binding
是最常用的绑定方式,使用stringformat
遵循.net格式字符串标准即可。
例如:
<textblock text="{binding price,elementname=self,stringformat={}{0:c}}"/>
或者
<textblock text="{binding teststring,elementname=self,stringformat=test:{0}}"/>
其中{0}
表示第一个数值,如果 stringformat
属性的值是以花括号开头,前边需要有一对花括号 {}
进行转义,也就是第一个例子中的 {}{0:c}
,否则不需要,如第二个示例一样。
如果设置 converter
和 stringformat
属性,则首先将转换器应用于数据值,然后stringformat
应用该值。
multibinding
binding
绑定时,格式化只能指定一个参数,multibinding
绑定时则可指定多个参数。
例如:
<textblock> <textblock.text> <multibinding stringformat="{}{0} {1}"> <binding path="firstname" elementname="self"/> <binding path="lastname" elementname="self"/> </multibinding> </textblock.text> </textblock>
这个例子中 multibinding
是由多个子 binding
组成,stringformat
仅在设置 multibinding
时适用,子 binding
中虽然也可以设置 stringformat
,但是会被忽略。
prioritybinding
相比于前两种绑定,prioritybinding
使用的频率没那么高,它的主要作用是按照一定优先级顺序设置绑定列表, 如果最高优先级绑定在处理时成功返回值,则无需处理列表中的其他绑定。
如果计算优先级最高的绑定需要很长时间,那么将会使用成功返回值的次高优先级,直到优先级较高的绑定成功返回值。
prioritybinding
和其包含的绑定列表中的子 binding
也都可以设置 stringformat
属性。
例如:
<textblock width="100" horizontalalignment="center" background="honeydew"> <textblock.text> <prioritybinding fallbackvalue="defaultvalue" stringformat="haha:{0}"> <binding isasync="true" path="slowestdp" stringformat="hi:{0}"/> <binding isasync="true" path="slowerdp" /> <binding path="fastdp" /> </prioritybinding> </textblock.text> </textblock>
与 multibinding
不同的是,prioritybinding
的子 binding
中的 stringformat
是会生效的,其规则是优先使用子 binding
设置的格式,其次才使用prioritybinding
设置的格式。
content属性格式化失效的原因
button
的 content
属性可以用字符串赋值并显示在按钮上,但是使用 stringformat
格式化并不会生效。
原本我以为是涉及到类型转换器,在类型转换过程中处理掉了,但这只是猜测,通过源码发现并不是这样的。
在 bindingexpressionbase
中有这样一段代码:
internal virtual bool attachoverride(dependencyobject target, dependencyproperty dp) { _targetelement = new weakreference(target); _targetproperty = dp; databindengine currentdatabindengine = databindengine.currentdatabindengine; if (currentdatabindengine == null || currentdatabindengine.isshutdown) { return false; } _engine = currentdatabindengine; determineeffectivestringformat(); determineeffectivetargetnullvalue(); determineeffectiveupdatebehavior(); determineeffectivevalidatesonnotifydataerrors(); if (dp == textbox.textproperty && isreflective && !isinbindingexpressioncollection && target is textboxbase textboxbase) { textboxbase.previewtextinput += onpreviewtextinput; } if (tracedata.isextendedtraceenabled(this, tracedatalevel.attach)) { tracedata.traceandnotifywithnoparameters(traceeventtype.warning, tracedata.attachexpression(tracedata.identify(this), target.gettype().fullname, dp.name, avtrace.gethashcodehelper(target)), this); } return true; }
其中第11行调用了一个名为 determineeffectivestringformat
的方法,顾名思义就是检测有效的 stringformat
。接下来看看里边的逻辑:
internal void determineeffectivestringformat() { type type = targetproperty.propertytype; if (type != typeof(string)) { return; } string stringformat = parentbindingbase.stringformat; for (bindingexpressionbase parentbindingexpressionbase = parentbindingexpressionbase; parentbindingexpressionbase != null; parentbindingexpressionbase = parentbindingexpressionbase.parentbindingexpressionbase) { if (parentbindingexpressionbase is multibindingexpression) { type = typeof(object); break; } if (stringformat == null && parentbindingexpressionbase is prioritybindingexpression) { stringformat = parentbindingexpressionbase.parentbindingbase.stringformat; } } if (type == typeof(string) && !string.isnullorempty(stringformat)) { setvalue(feature.effectivestringformat, helper.geteffectivestringformat(stringformat), null); } }
这段代码的作用就是检测有效的 stringformat
,并通过 setvalue
方法保存起来,从第4~7行代码可以看到,一开始就会检测目标属性的类型是不是 string
类型,不是的话直接返回,绑定表达式中的 stringformat
也就不会保存了。
在后续的 bindingexpression
类计算绑定表达式值时获取到 stringformat
为 null
,也就不会进行格式化了。
button
的 content
属性虽然可以用字符串赋值,但它其实的 object
类型。因此,在检测有效的 stringformat
表达式时直接过滤了。tooltip
也同样是 object
类型。
解决方法
对于 content
这种 object
类型的属性绑定字符串并且需要格式化时,可以采用以下三种方式解决:
1、最通用的方法就是自定义 valueconverter
,在 valueconverter
中对字符串进行格式化;
2、绑定到其他可进行 stringformat
的属性上,比如 textblock
的 text
属性进行格式化,tooltip
绑定到 text
上;
3、既然是 object
类型,那也可把 textblock
作为 content
的值。
<button width="120" height="30"> <button.content> <textblock text="{binding teststring,elementname=self,stringformat=test:{0}}"/> </button.content> </button>
小结
数据绑定时出现stringformat失效的主要分为两种情况。一是没有遵循绑定时stringformat使用的约束,二是绑定的目标属性不是 string
类型。
最后
以上就是wpf数据绑定时出现stringformat失效的原因和解决方法的详细内容,更多关于wpf stringformat失效的资料请关注代码网其它相关文章!
发表评论