使用 StringFormat 的 WPF 绑定不适用于工具提示

下面的代码有一个简单的绑定,它使用完全相同的绑定符号将名为 MyTextBlock 的 TextBlock 的 Text 绑定到 TextBox 的 Text 和 ToolTip 属性:

<StackPanel>
<TextBlock x:Name="MyTextBlock">Foo Bar</TextBlock>
<TextBox    Text="{Binding ElementName=MyTextBlock, Path=Text, StringFormat='It is: \{0\}'}"
ToolTip="{Binding ElementName=MyTextBlock, Path=Text, StringFormat='It is: \{0\}'}" />
</StackPanel>

绑定还使用了 由.NET 3.5 SP1引入的 StringFormat 属性,该 由.NET 3.5 SP1引入的 StringFormat 属性在上面的 Text 属性中工作得很好,但是在工具提示中似乎出现了故障。预期的结果是“ It is: Foo Bar”,但是当鼠标悬停在 TextBox 上时,工具提示只显示绑定值,而不显示字符串格式的值。有什么想法吗?

32606 次浏览

ToolTips in WPF can contain anything, not just text, so they provide a ContentStringFormat property for the times you just want text. You'll need to use the expanded syntax as far as I know:

<TextBox ...>
<TextBox.ToolTip>
<ToolTip
Content="{Binding ElementName=myTextBlock,Path=Text}"
ContentStringFormat="{}It is: {0}"
/>
</TextBox.ToolTip>
</TextBox>

I'm not 100% sure about the validity of binding using the ElementName syntax from a nested property like that, but the ContentStringFormat property is what you're looking for.

The following is a wordy solution but it works.

<StackPanel>
<TextBox Text="{Binding Path=., StringFormat='The answer is: {0}'}">
<TextBox.DataContext>
<sys:Int32>42</sys:Int32>
</TextBox.DataContext>
<TextBox.ToolTip>
<ToolTip Content="{Binding}" ContentStringFormat="{}The answer is: {0}" />
</TextBox.ToolTip>
</TextBox>
</StackPanel>

I would prefer a much simpler syntax, something like the one in my original question.

Your code can be as short as this:

<TextBlock ToolTip="{Binding PrideLands.YearsTillSimbaReturns,
Converter={StaticResource convStringFormat},
ConverterParameter='Rejoice! Just {0} years left!'}" Text="Hakuna Matata"/>

We'll use the fact Converters are never ignored, unlike StringFormat.

Put this into StringFormatConverter.cs:

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;


namespace TLKiaWOL
{
[ValueConversion (typeof(object), typeof(string))]
public class StringFormatConverter : IValueConverter
{
public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
{
if (ReferenceEquals(value, DependencyProperty.UnsetValue))
return DependencyProperty.UnsetValue;
return string.Format(culture, (string)parameter, value);
}


public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

Put this into your ResourceDictionary.xaml:

<conv:StringFormatConverter x:Key="convStringFormat"/>

As Matt said ToolTip can contain anything inside so for your you could bind a TextBox.Text inside your ToolTip.

<StackPanel>
<TextBlock x:Name="MyTextBlock">Foo Bar</TextBlock>
<TextBox Text="{Binding ElementName=MyTextBlock, Path=Text, StringFormat='It is: \{0\}'}">
<TextBox.ToolTip>
<TextBlock>
<TextBlock.Text>
<Binding ElementName=MyTextBlock Path="Text" StringFormat="It is: {0}" />
</TextBlock.Text>
</TextBlock>
</TextBox.ToolTip>
</TextBox>
</StackPanel>

Even you can Stack a grid inside the ToolTip and layout your text if you want.

It could be a bug. When you use short syntax for tooltip:

<TextBox ToolTip="{Binding WhatEverYouWant StringFormat='It is: \{0\}'}" />

StringFormat is ignore but when you use expanded syntax:

<TextBox Text="text">
<TextBox.ToolTip>
<TextBlock Text="{Binding WhatEverYouWant StringFormat='It is: \{0\}'}"/>
</TextBox.ToolTip>
</TextBox>

It works as expected.

In this situation, you can use relative binding:

<StackPanel>
<TextBlock x:Name="MyTextBlock">Foo Bar</TextBlock>
<TextBox Text="{Binding ElementName=MyTextBlock, Path=Text, StringFormat='It is: \{0\}'}"
ToolTip="{Binding Text, RelativeSource={RelativeSource Self}}" />
</StackPanel>