Location>code7788 >text

[WPF] Why StringFormat fails during data binding

Popularity:340 ℃/2024-08-30 13:05:40

In the data binding process, we often use theStringFormatThe data to be displayed is formatted for a more intuitive presentation, but in some cases the formatting does not take effect, for exampleButton(used form a nominal expression)Contentattributes as well asToolTipAttribute binding data is performedStringFormatwhen it is invalid. First review theStringFormatThe basic usage of the

StringFormatusage

StringFormatbeBindingBaseproperty that specifies how the binding should be formatted if the binding value is displayed as a string. Thus, theBindingBase The three subclasses of theBindingMultiBindingPriorityBindingBoth can format the bound data.

Binding

Binding is the most common binding method, using theStringFormatcomply withNet format string standardcan be done. Example:

<TextBlock Text="{Binding Price,ElementName=self,StringFormat={}{0:C}}"/>

or

<TextBlock Text="{Binding TestString,ElementName=self,StringFormat=test:{0}}"/>

included among these{0}denotes the first value ifStringFormat The value of an attribute begins with a pair of curly braces, which need to be preceded by a pair of braces{} is escaped, i.e., the first example of the{}{0:C}, otherwise not required, as in the second example.
If you set theConverter cap (a poem)StringFormatattribute, then the converter is first applied to the data value and theStringFormat Apply the value.

MultiBinding

Binding When binding, formatting can only specify one parameter, theMultiBinding For binding then multiple parameters can be specified. Example:

<TextBlock>
    <>
        <MultiBinding StringFormat="{}{0} {1}">
            <Binding Path="FirstName" ElementName="self"/>
            <Binding Path="LastName" ElementName="self"/>
        </MultiBinding>
    </>
</TextBlock>

In this exampleMultiBinding is composed of multiple subBinding Composition.StringFormat Only when setting theMultiBinding When applicable, the subBinding Although it is possible to set theStringFormat, but will be ignored.

PriorityBinding

Compared to the first two bindings, thePriorityBinding It is not used that often, but its main purpose is to set up the list of bindings in a certain priority order, so that if the highest priority binding returns a value when processed, the other bindings in the list do not need to be processed. If it takes a long time to compute the highest priority binding, then the next highest priority will be used until the higher priority binding returns a successful value.PriorityBinding and the children in the list of bindings it contains.Binding All of them can also be setStringFormat Attributes. Example:

<TextBlock
    Width="100"
    HorizontalAlignment="Center"
    Background="Honeydew">
    <>
        <PriorityBinding FallbackValue="defaultvalue" StringFormat="haha:{0}">
            <Binding IsAsync="True" Path="SlowestDP" StringFormat="hi:{0}"/>
            <Binding IsAsync="True" Path="SlowerDP" />
            <Binding Path="FastDP" />
        </PriorityBinding>
    </>
</TextBlock>

together withMultiBinding The difference is thatPriorityBinding son ofBindinghit the nail on the headStringFormatis going to take effect, the rule is to prioritize the use of subBinding set format, and only secondarily use thePriorityBinding The format of the setting.

Reasons why the formatting of the Content attribute is not working

Button (used form a nominal expression)Content attribute can be assigned with a string and displayed on the button, but using theStringFormat Formatting doesn't take effect. Originally I thought it was a type converter involved, and that it was handled during the type conversion process, but that was just a guess, and I found out through the source code that this is not the case. In theBindingExpressionBase There is a piece of code like this:

internal virtual bool AttachOverride(DependencyObject target, DependencyProperty dp)
{
	_targetElement = new WeakReference(target);
	_targetProperty = dp;
	DataBindEngine currentDataBindEngine = ;
	if (currentDataBindEngine == null || )
	{
		return false;
	}
	_engine = currentDataBindEngine;
	DetermineEffectiveStringFormat();
	DetermineEffectiveTargetNullValue();
	DetermineEffectiveUpdateBehavior();
	DetermineEffectiveValidatesOnNotifyDataErrors();
	if (dp ==  && IsReflective && !IsInBindingExpressionCollection && target is TextBoxBase textBoxBase)
	{
		 += OnPreviewTextInput;
	}
	if ((this, ))
	{
		(, ((this), ().FullName, , (target)), this);
	}
	return true;
}

where line 11 calls a program calledDetermineEffectiveStringFormat The method, as the name suggests, is to detect effectiveStringFormat. Next look at the logic inside:

internal void DetermineEffectiveStringFormat()
{
	Type type = ;
	if (type != typeof(string))
	{
		return;
	}
	string stringFormat = ;
	for (BindingExpressionBase parentBindingExpressionBase = ParentBindingExpressionBase; parentBindingExpressionBase != null; parentBindingExpressionBase = )
	{
		if (parentBindingExpressionBase is MultiBindingExpression)
		{
			type = typeof(object);
			break;
		}
		if (stringFormat == null && parentBindingExpressionBase is PriorityBindingExpression)
		{
			stringFormat = ;
		}
	}
	if (type == typeof(string) && !(stringFormat))
	{
		SetValue(, (stringFormat), null);
	}
}

What this code does is detect validStringFormatand throughSetValue method is saved, and as you can see from lines 4 to 7 of the code, at the outset it detects whether the type of the target attribute isString type, if it is not, it is returned directly, and the binding expression in theStringFormat It wouldn't have been saved. In the subsequentBindingExpression class gets the value of the binding expression when it calculates the value of theStringFormat because ofnulland it would not be formatted.
image

Button (used form a nominal expression)Content property can be assigned with a string, but it's actually theObject Type. Therefore, it is important to be able to detect a validStringFormat expression is filtered directly.ToolTipLikewise.Object Type.
image

cure

insofar asContent this kind ofObject When a property of a type is bound to a string and needs to be formatted, it can be resolved in the following three ways:

  1. The most versatile method is to customize theValueConverterinValueConverter The string is formatted in the
  2. Binds to other programs that can performStringFormat on attributes such asTextBlock (used form a nominal expression)Text attribute is formatted.ToolTip Bind toText Up;
  3. since it isObject type, that can also be putTextBlock act asContentThe value of the
<Button Width="120" Height="30">
    <>
        <TextBlock Text="{Binding TestString,ElementName=self,StringFormat=test:{0}}"/>
    </>
</Button>

wrap-up

There are two main cases where StringFormat failure occurs during data binding. One is that the constraints on the use of StringFormat when binding are not followed, and the other is that the target property of the binding is not theString Type.