WPF数据绑定时出现StringFormat失效的原因和解决方法

 更新时间:2024年12月10日 11:13:36   作者:小码编匠  
在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,所以本文介绍了WPF数据绑定时出现StringFormat失效的原因和解决方法,需要的朋友可以参考下

前言

在数据绑定过程中,我们经常会使用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},否则不需要,如第二个示例一样。

如果设置 ConverterStringFormat属性,则首先将转换器应用于数据值,然后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,也就不会进行格式化了。

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

解决方法

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

最后

以上就是WPF数据绑定时出现StringFormat失效的原因和解决方法的详细内容,更多关于WPF StringFormat失效的资料请关注脚本之家其它相关文章!

相关文章

  • gridview的buttonfield获取该行的索引值(实例讲解)

    gridview的buttonfield获取该行的索引值(实例讲解)

    本篇文章主要介绍了gridview的buttonfield获取该行的索引值(实例讲解)需要的朋友可以过来参考下,希望对大家有所帮助
    2014-01-01
  • C# WinForm RichTextBox文本动态滚动显示文本方式

    C# WinForm RichTextBox文本动态滚动显示文本方式

    这篇文章主要介绍了C# WinForm RichTextBox文本动态滚动显示文本方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • C# as 和 is 运算符区别和用法示例解析

    C# as 和 is 运算符区别和用法示例解析

    在C#中,as 和 is 关键字都用于处理类型转换的运算符,但它们有不同的用途和行为,本文我们将详细解释这两个运算符的区别和用法,需要的朋友可以参考下
    2025-01-01
  • c# 使用Task实现非阻塞式的I/O操作

    c# 使用Task实现非阻塞式的I/O操作

    这篇文章主要介绍了c# 使用Task实现非阻塞式的I/O操作,帮助大家更好的理解和学习c# 编程语言,感兴趣的朋友可以了解下
    2020-11-11
  • C#关于Textbox滚动显示最后一行,不闪烁问题

    C#关于Textbox滚动显示最后一行,不闪烁问题

    这篇文章主要介绍了C#关于Textbox滚动显示最后一行,不闪烁问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • c# NPOI 如何在指定单元格导入导出图片

    c# NPOI 如何在指定单元格导入导出图片

    这篇文章主要介绍了c# NPOI 如何在指定单元格导入导出图片,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • C#中的Linq to Xml详解

    C#中的Linq to Xml详解

    这篇文章主要介绍了C#中的Linq to Xml详解,本文给出转换步骤以及大量实例,讲解了生成xml、查询并修改xml、监听xml事件、处理xml流等内容,需要的朋友可以参考下
    2015-01-01
  • c#访问this关键字和base关键字示例

    c#访问this关键字和base关键字示例

    this关键字引用类的当前实例。静态成员方法中不能使用this关键字,this关键字只能在实例构造函数、实例方法或实例访问器中使用。base关键字用于从派生类中访问基类的成员。下面学习一下这二个关键字的使用方法
    2014-01-01
  • C#基于百度AI实现机器翻译功能

    C#基于百度AI实现机器翻译功能

    众所周知,基于百度ai开发平台我们可以实现了人脸识别、文字识别 、语音识别等功能。本文将介绍它的另一个功能,即实现机器翻译,感兴趣的可以了解一下
    2022-01-01
  • C#播放背景音乐的方法小结

    C#播放背景音乐的方法小结

    这篇文章主要介绍了C#播放背景音乐的方法,实例总结了C#播放背景音乐的相关技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04

最新评论