首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

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

编程知识
2024年08月30日 12:07

在数据绑定过程中,我们经常会使用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 属性。例如:

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

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 类型。

From:https://www.cnblogs.com/czwy/p/18388552
本文地址: http://shuzixingkong.net/article/1582
0评论
提交 加载更多评论
其他文章 POA:已开源,蚂蚁集团提出同时预训练多种尺寸网络的自监督范式 | ECCV 2024
论文提出一种新颖的POA自监督学习范式,通过弹性分支设计允许同时对多种尺寸的模型进行预训练。POA可以直接从预训练teacher生成不同尺寸的模型,并且这些模型可以直接用于下游任务而无需额外的预训练。这个优势显著提高了部署灵活性,并有助于预训练的模型在各种视觉任务中取得SOTA结果。 来源:晓飞的算
POA:已开源,蚂蚁集团提出同时预训练多种尺寸网络的自监督范式 | ECCV 2024 POA:已开源,蚂蚁集团提出同时预训练多种尺寸网络的自监督范式 | ECCV 2024 POA:已开源,蚂蚁集团提出同时预训练多种尺寸网络的自监督范式 | ECCV 2024
投屏协议
AirPlay协议是苹果开发、广泛应用于iPhone、iPad和Mac设备,可以通过WiFi将iPhone、iPad等iOS设备上的图片、音频、视频通过无线的方式传输到支持AirPlay 设备。即移动终端显示什么电视大屏就显示什么。随着AirPlay协议逐步普及,国内越来越多网络机顶盒,智能电视都集
服务重启了,如何保证线程池中的数据不丢失?
大家好,我是苏三,又跟大家见面了。 前言 最近有位小伙伴在我的技术群里,问了我一个问题:服务down机了,线程池中如何保证不丢失数据? 这个问题挺有意思的,今天通过这篇文章,拿出来跟大家一起探讨一下。 1 什么是线程池? 之前没有线程池的时候,我们在代码中,创建一个线程有两种方式: 继承Thread
服务重启了,如何保证线程池中的数据不丢失? 服务重启了,如何保证线程池中的数据不丢失? 服务重启了,如何保证线程池中的数据不丢失?
工作 6 年,@Transactional 注解用的一塌糊涂
接手新项目一言难尽,别的不说单单就一个 @Transactional 注解用的一塌糊涂,五花八门的用法,很大部分还失效无法回滚。 有意识的在涉及事务相关方法上加@Transactional注解,是个好习惯。不过,很多同学只是下意识地添加这个注解,一旦功能正常运行,很少有人会深入验证异常情况下事务是否
工作 6 年,@Transactional 注解用的一塌糊涂
折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪
概述 分布式追踪是一种跟踪应用程序请求流经不同服务(如前端、后端、数据库等)的过程。它是一个强大的工具,可以帮助您了解应用程序的工作原理并调试性能问题。 Quickwit 是一个用于索引和搜索非结构化数据的云原生引擎,这使其非常适合用作追踪数据的后端。 此外,Quickwit 本地支持 OpenTe
折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪 折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪 折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪
从代码到产品,我的IT职业成长之路
每个人的职业生涯都是一段充满转折和挑战的旅程,当然每一次职业转型都是一次重新定义自己的机会,从2015年开始,当时我刚踏入IT行业,成为一名Java开发者,后来随着时间的推移,我的职业方向逐渐转向了前端开发者,埋头于代码的世界。最终在2018年找到了属于自己的职业定位——产品经理。一路走来,我不断扩
从代码到产品,我的IT职业成长之路
基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型
过去的几个月,我们目睹了使用基于 transformer 模型作为扩散模型的主干网络来进行高分辨率文生图 (text-to-image,T2I) 的趋势。和一开始的许多扩散模型普遍使用 UNet 架构不同,这些模型使用 transformer 架构作为扩散过程的主模型。由于 transformer
基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型 基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型 基于 Quanto 和 Diffusers 的内存高效 transformer 扩散模型
Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储
Clobotics 是一家将计算机视觉和机器学习技术应用于风电以及零售行业的企业。在风电行业,Clobotics 利用无人机对风力发电机叶片进行检查,显著降低了对人工作业的依赖。在零售领域,公司通过分析捕获的包装商品图像来提供基于实时数据的洞察,以增加销售额并减少运营成本。 存储方面,Cloboti
Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储 Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储 Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储