[WPF]数据绑定时为何会出现StringFormat失效

news/2024/10/6 14:33:57

在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如 ButtonContent属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。

StringFormat的用法

StringFormatBindingBase的属性,指定如果绑定值显示为字符串,应如何设置该绑定的格式。因此,BindingBase 的三个子类:BindingMultiBindingPriorityBinding都可以对绑定数据进行格式化。

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 属性。例如:

<TextBlockWidth="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属性格式化失效的原因

ButtonContent 属性可以用字符串赋值并显示在按钮上,但是使用 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 类计算绑定表达式值时获取到 StringFormatnull,也就不会进行格式化了。
image

ButtonContent 属性虽然可以用字符串赋值,但它其实的 Object 类型。因此,在检测有效的 StringFormat 表达式时直接过滤了。ToolTip也同样是 Object 类型。
image

解决方法

对于 Content 这种 Object 类型的属性绑定字符串并且需要格式化时,可以采用以下三种方式解决:

  1. 最通用的方法就是自定义 ValueConverter,在 ValueConverter 中对字符串进行格式化;
  2. 绑定到其他可进行 StringFormat 的属性上,比如 TextBlockText 属性进行格式化,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 类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/54631.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

GDB调试器使用指南:设置断点、单步调试和查看寄存器状态

介绍了使用ddd进行C程序的调试过程,包括设置断点、单步调试、查看寄存器状态等操作。通过图示展示了相关操作步骤,帮助用户更好地理解调试工具的使用方法。使用 ​ddd ./eg​ 设置 ​​ 断点 ​​ 运行 ​​ 点击​run​​ 单步调试 ​Next​命令将执行到下一条指令。 这包括…

基于Swagger自动生成离线API文档(Word、Markdown文档)

在做项目时通常需要给客户提供离线Word的API文档归档,不要跟客户说有Swagger在线API文档,客户不会用也不会去看。只要你有Swagger,TableGo就能自动生成一份漂亮的Word离线API文档给客户,大大提高了写文档的效率,客户看了高兴,大家项目交付的速度也快很多。支持Swagger2和…

一次简单的脱壳

涉及:ESP 定律 例:https://files.cnblogs.com/files/blogs/824994/Magic_Shell.zip?t=1724993084&download=true x64dbg 打开 -> 符号 -> magic_shell.exe下断点F9 运行到 EP单步过 push,能看见 RSP 的值变红根据 ESP 定律,下硬件断点F9 跳转后在最近的 jmp 跳转…

【日记】现在问题变成买哪一台电脑了(344 字)

正文今天领了家电补贴,原本就有换电脑的计划和打算,这下想换电脑的心情越来越强烈了。昨天跟母亲打电话,她跟我聊到有光伏公司跟他们抢生意。虽然这事挺搞,但我还觉得蛮有意思。我万万没想到商战这种事情能发展到我们村里……检查基本已经结束了,没有前阵子那样特别忙碌了…

sata转USB连接硬盘

打开设备管理器,查看硬盘驱动是否为 标准 SATA AHCI 控制器,再查看所添加的硬盘的Bus Number是多少。 然后打开注册表编辑器,进入 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\storahci\Parameters\Device,右键点击Device,然后“新建”→”多字符串值”…

是德科技 34465A、34461A系列万用表安捷伦

1. 是德科技生产的台式6位半万用表,原来是安捷伦,改名为是德科技,功能强大,准确度高,主要测量功能如下2. 支持触发测量,不过只有 34465 + DIG选件可以。支持滤波,减少高频噪声 3. 可以设置NPLC,外接电源的一个测量周期,收集这些值进行平均,可以消除电源的影响 4. 支持…

智慧工厂视频监控解决方案

智能工厂视频监控解决方案以地区生态环境和工厂污染物为关键监控目标。根据线上监控人工智能技术剖析,智能工厂视频监控解决方案24钟头连续不断监控。安全性基本建设已变成当代工厂管理方法的关键构成部分。视频监控系统可以在范围内组装视频监控系统,统一操纵和管理方法出入…

平安校园视频监控方案

平安校园视频监控方案部署一台SuiJi-AI100视频分析服务器,使用校园视频监控智方案能分析仪进行视频取流和视频告警事件的处理,生成告警事件和记录,并进行系统的数据展示和应用,并可联动IP音箱进行告警事件语音广播和实时广播喊话。平安校园视频监控方案部署一台SuiJi-AI100…