2

I'm trying to change the PlacementTarget of a ToolTip to a window further up the visual tree in order to have custom ToolTip clipping effects in that window. I've hooked everything up except for the PlacementTarget. Here's an example from XAML and in code...neither work. This style is currently being used for a single tooltip attached to a TextBox.

<Style TargetType="ToolTip">
    <Setter Property="ToolTipService.PlacementTarget"
            Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                AncestorType={x:Type Grid }} }" />
</Style>

If I go into code and look at the tooltip.PlacementTarget once it's attached to something...it's always set to the TextBox. I've tried multiple ways of using the VisualTree to get different UIElements. Nothing seems to work...so I'm assuming I'm not understanding or missing something.

The thing that really gets me is that if I go into my code and look at the PlacementTarget of the tooltip, it won't let me set it to anything else. For instance:

var ancestors = toolTip.PlacementTarget.GetSelfAndAncestors();

foreach(var ancestor in ancestors)
{
    if(var ancestor is Grid)
    {
        // Conditional always hits.
        // Before this line, PlacementTarget is a TextBox.
        toolTip.PlacementTarget = (UIElement)ancestor;  
        // After the line, PlacementTarget is still a TextBox.
    }
}

What am I doing incorrectly or not understanding?

Edit for Context: The custom clipping effect is to basically just find the closest ancestor window to the ToolTip's target and use that to make sure the ToolTip never goes outside the bounds of that window.

user2079828
  • 645
  • 1
  • 8
  • 31
  • WPF's a bit messy with the way its tooltips work with `PlacementTarget` and `DataContext`. it gets configusing fast ; take a look at https://stackoverflow.com/questions/6783693/how-to-set-a-placementtarget-for-a-wpf-tooltip-without-messing-up-the-datacontex – Timothy Groote Jun 16 '17 at 07:17
  • How is your visual tree defined? A Tooltip resides in its own visual tree and won't be able to use a RelativeSource to find something in the parent window. – mm8 Jun 16 '17 at 12:24
  • @TimothyGroote Thanks, I'll check it out. To mm8, I thought that the RelativeSource value would first target the default target (The TextBox in this case) and move up their visual tree to find the first Grid (maybe I need to set AnscestorLevel to 1, though). However,I can't get any value to actually set the PlacementTarget, regardless. – user2079828 Jun 16 '17 at 14:50

1 Answers1

4

A short sample setting a Tooltip, using a property on the parent Window as PlacementTarget.

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Tag="Bar">
    <Window.Resources>
        <ToolTip x:Key="FooToolTip">
            <StackPanel>
                <TextBlock Text="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}"/>
            </StackPanel>
        </ToolTip>
    </Window.Resources>
    <Grid>
        <TextBlock 
            Text="Foo"
            ToolTip="{StaticResource FooToolTip}"
            ToolTipService.PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
            HorizontalAlignment="Center" VerticalAlignment="Center" Height="20" Width="50">
        </TextBlock>
    </Grid>
</Window>

EDIT

To answer your questions,

the first snippet uses ToolTipService in the wrong way:

The ToolTipService class attached properties are used to determine the placement, behavior, and appearance of a tooltip. These properties are set on the element that defines the tooltip.

Applied in a style:

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Tag="Bar">
    <Window.Resources>
        <ToolTip x:Key="FooToolTip">
            <StackPanel>
                <TextBlock Text="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}"/>
            </StackPanel>
        </ToolTip>
        <Style x:Key="ToolTipStyle">
            <Setter Property="ToolTipService.ToolTip" Value="{StaticResource FooToolTip}"/>
            <Setter Property="ToolTipService.PlacementTarget" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBlock 
            Text="Foo" Style="{StaticResource ToolTipStyle}"
            HorizontalAlignment="Center" VerticalAlignment="Center" Height="20" Width="50">
        </TextBlock>
    </Grid>
</Window>

As for your second snippet in code behind, you can't set the PlacementTarget once the ToolTip is open and when the ToolTip is closed the PlacementTarget is null. As @mm8 pointed out, this has to do with the ToolTip and the PlacementTarget being in different visual trees, since a ToolTip spawns a Window of its own.

Funk
  • 10,976
  • 1
  • 17
  • 33
  • I've seen this, and it (possibly) solves my problems, but doesn't really answer the question. What exactly is incorrect about the two code snippets? Why can't I set the PlacementTarget programmatically in the second one? – user2079828 Jun 16 '17 at 14:51
  • Also, it needs to be set in a tooltip style since I'm not putting the placementTarget in every single control I want the style to work with. – user2079828 Jun 16 '17 at 15:11
  • I used your explanation to get me going. I was able to solve it by creating a child class to Behavior which attaches a property in xaml to any given behavior (Based on https://stackoverflow.com/questions/1647815/how-to-add-a-blend-behavior-in-a-style-setter). I then place a tag on the window and set a tooltip style using my behavior. It searches for the first ancestor which matches the tag and uses its properties to fit the popup. This allows me to set one tooltip style per view and place tags on windows I want the tooltips to fit into. Requires no work in individual controls. – user2079828 Jun 17 '17 at 20:33
  • I've accepted your answer since it explains why what I was doing does not work. – user2079828 Jun 17 '17 at 20:34