In the data binding process, we often use theStringFormat
The 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)Content
attributes as well asToolTip
Attribute binding data is performedStringFormat
when it is invalid. First review theStringFormat
The basic usage of the
StringFormat
usage
StringFormat
beBindingBase
property that specifies how the binding should be formatted if the binding value is displayed as a string. Thus, theBindingBase
The three subclasses of theBinding
、MultiBinding
、PriorityBinding
Both can format the bound data.
Binding
Binding
is the most common binding method, using theStringFormat
comply 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)StringFormat
attribute, 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 ofBinding
hit the nail on the headStringFormat
is 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 validStringFormat
and 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 ofnull
and it would not be formatted.
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.ToolTip
Likewise.Object
Type.
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:
- The most versatile method is to customize the
ValueConverter
inValueConverter
The string is formatted in the - Binds to other programs that can perform
StringFormat
on attributes such asTextBlock
(used form a nominal expression)Text
attribute is formatted.ToolTip
Bind toText
Up; - since it is
Object
type, that can also be putTextBlock
act asContent
The 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.