1

I am trying to create a textblock that shows a tooltip of the textblock's text when its being trimmed. I have the actual visibility part of this taken care of in a converter. My problem is binding the ToolTip's content to its partent textblock's text. I have been fiddling with different relative paths for awhile now and can never get anything but a blank tooltip. The text shows up fine when I want if I hardcode something in the tooltips content.

<Style x:Key="InfoToolTipBaseTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockBase}">
    <Setter Property="ToolTip">
        <Setter.Value>
            <ToolTip Visibility="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget, Converter={StaticResource TrimmedVisibilityConverter}}" Content="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBlock}}}"/>                
        </Setter.Value>
    </Setter>
</Style>
Derek Meyer
  • 497
  • 7
  • 22

2 Answers2

3

Instead of creating a tooltip that's always there, setting its content, and then switching its visibility, just have a style trigger on the TextBlock that sets the ToolTip property to Text when needed.

I've used your existing converter, but you might want to rewrite it to return bool. Then you'd have Value="True" in the DataTrigger.

<Style 
    x:Key="InfoToolTipBaseTextBlockStyle" 
    TargetType="{x:Type TextBlock}" 
    BasedOn="{StaticResource TextBlockBase}"
    >
    <Style.Triggers>
        <DataTrigger 
            Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TrimmedVisibilityConverter}}"
            Value="Visible"
            >
            <Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Self}}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

I don't know if this is an issue for you, but if Text changes at runtime, the the tooltip won't be updated, because that Binding doesn't know you care about the Text property. The fix for that would be to rewrite the converter as IMultiValueConverter so you can use it with a MultiBinding that would have bindings to Text as well as Self. It wouldn't have to use Text, but it would update the target when Text changes.

A better solution, simpler and WPFish, would be to write a behavior for TextBlock that recycles the guts of your converter, handles change notifications on Text, and updates an attached TextBlockExt.IsTextElided bool property on the TextBlock.

  • 1
    I figured it out. I updated the converter to return a bool but not the value in the data trigger value binding. Working fine now thanks! Im amazed there isnt an easier native way to do this as i would think its a common problem. – Derek Meyer Jan 03 '18 at 16:47
  • Thanks @Ed . This was bugging me. – Derek Meyer Jan 03 '18 at 16:54
  • 1
    You're quite welcome. I regret that TextBlock doesn't have a property that indicates whether the Text is currently elided. That would be in the spirit of WPF. In fact, it shouldn't be at all hard to write a behavior for TextBlock that recycles the guts of your converter, handles change notifications on Text, and updates an attached `TextBlockExt.IsTextElided` bool property on the TextBlock. – 15ee8f99-57ff-4f92-890c-b56153 Jan 03 '18 at 16:57
  • ha maybe I spoke too soon.. I could have sworn this was working before i went to lunch, but now the converter, when checking on the actual width, always has a value of zero, so it always returns true. Fantastic disappointment :( – Derek Meyer Jan 03 '18 at 18:52
  • My first wild guess that it's being invoked just once -- on creation, before the TextBlock gets its text. I'd look at the MultiConverter/MultiBinding thing, and bind (but not use) Text so it'll update every time Text changes. – 15ee8f99-57ff-4f92-890c-b56153 Jan 03 '18 at 18:54
  • I thought that too but the framework element is showing the text having the expected value. Not sure if it has to render first or something. Back to tinkering. – Derek Meyer Jan 03 '18 at 19:01
  • Maybe go back to the behavior idea -- write a behavior that handles `SizeChanged` on the TextBlock. Every time the size changes it checks if it's elided and sets an `IsTextElided` attached property to true or false. – 15ee8f99-57ff-4f92-890c-b56153 Jan 03 '18 at 19:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/162453/discussion-between-derek-meyer-and-ed-plunkett). – Derek Meyer Jan 03 '18 at 19:49
2

Solved it simply by this.

        <Style x:Key="InfoToolTipBaseTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockBase}">
            <Setter Property="ToolTip">
                <Setter.Value>
                    <ToolTip Visibility="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget, Converter={StaticResource TrimmedVisibilityConverter}}"
                             Content="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.Text}"/>
                </Setter.Value>
            </Setter>
        </Style>
Derek Meyer
  • 497
  • 7
  • 22