WPF binding with StringFormat doesn't work on ToolTips
WpfBindingWpf Problem Overview
The following code has a simple binding which binds the Text of the TextBlock named MyTextBlock to TextBox's Text and ToolTip property using the exact same Binding notation:
<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>
The binding also uses the StringFormat property introduced with .NET 3.5 SP1 which is working fine for the above Text property but seems to be broken for the ToolTip. The expected result is "It is: Foo Bar" but when you hover over the TextBox, the ToolTip shows only the binding value, not the string formatted value. Any ideas?
Wpf Solutions
Solution 1 - Wpf
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.
Solution 2 - Wpf
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.
Solution 3 - Wpf
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.
Solution 4 - Wpf
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"/>
Solution 5 - Wpf
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>
Solution 6 - Wpf
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.