We have many TextBlocks in our application and many of them must have ToolTips.
Often the ToolTip should display the same as the TextBlock.Text property.
Also the ToolTip should not be displayed if the TextBlock.Text = "" or null.
So we have this solution in many many places:
<TextBlock Text="{Binding SomeTextProperty}">
<TextBlock.ToolTip>
<ToolTip Visibility="{Binding SomeTextProperty}, Converter={StaticResource StringToVisibilityConverter}">
<TextBlock Text="{Binding SomeTextProperty}" />
</TextBlock.ToolTip>
</TextBlock>
Notice:
- I have to specify the
SomeTextPropertythree times on each TextBlock that need a TooLTip with this functionality.
This seems very redundant! - The
ToolTip.Contentis a TextBlock itself.
This is because I need to have a Style on the TextBlock.
I have omitted that style to keep this post as simple as possible.
So I have tried to invent a Style for TextBlocks that use Bindings with RelativeSource to get the TextBlock.Text property for the ToolTip. I came up with this solution:
MainWindow (Just copy-paste more or less)
<Window x:Class="Main.Views.ToolTips"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Main.Views"
xmlns:converters="clr-namespace:Main.Converters"
mc:Ignorable="d"
Title="ToolTips" Height="450" Width="800">
<Window.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockWithToolTipStyle">
<Style.Resources>
<converters:StringToVisibilityConverter x:Key="StringToVisibilityConverter" />
</Style.Resources>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Visibility="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type TextBlock}}, Converter={StaticResource StringToVisibilityConverter}}">
<ToolTip.Content>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBlock}}}" />
</ToolTip.Content>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="This should display a tooltip" />
<TextBlock Text="asdf"
Background="Gray"
Style="{StaticResource TextBlockWithToolTipStyle}" />
<Separator Height="50" Visibility="Hidden" />
<TextBlock Text="This should not display a tooltip" />
<TextBlock Text=""
Background="LightGray"
Style="{StaticResource TextBlockWithToolTipStyle}" />
</StackPanel>
</Window>
StringToVisibilityConverter
public class StringToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var input = value is null ? string.Empty : value.ToString();
return string.IsNullOrWhiteSpace(input) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
This, of course, don't work!
I put a breakpoint in the StringToVisibilityConverter and that breakpoint is not hit when I hover both TextBlocks in the Window.
In VS's XAML Binding Failures view I see two binding errors that regards ToolTip.Visibility and TextBlock.Text:
- ToolTip.Visibility: Cannot find source: RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TextBlock', AncestorLevel='1'
- TextBlock.Text: Cannot find source: RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TextBlock', AncestorLevel='1'
Is this possible to solve?
If so, how?
/BR, Steffe
The
ToolTipis not part of the visual tree. That's why yourBinding.RelativeSourcedoes not resolve.To reference the element that is decorated by the
ToolTipyou must reference theToolTip.PlacementTargetproperty:Furthermore, you should not try to toggle the
ToolTip.Visibility. It won't work. Instead use aTriggerto set theToolTip.The correct solution would be as followed: