Find ToolTip Popup in Logical or Visual Tree

c#, wpf

Solution

A `ToolTip` is a kind of `Popup` which hosts the tooltip content

And since a Popup is hosted in a separate window so it have it's own logical and visual tree

for your information below are the Visual and Logical tree for a tooltip

Visual Tree

System.Windows.Controls.Primitives.PopupRoot
  System.Windows.Controls.Decorator
    System.Windows.Documents.NonLogicalAdornerDecorator
      System.Windows.Controls.ToolTip

Logical Tree

System.Windows.Controls.Primitives.Popup
  System.Windows.Controls.ToolTip

Note: since popup has it's own root so it may not be accessible from main window's visual or logical tree.

To find a popup of tool tip

I have used attached properties to find the popup for a tooltip

namespace CSharpWPF
{

    public class ToolTipHelper : DependencyObject
    {
        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(ToolTipHelper), new PropertyMetadata(false,OnEnable));

        private static void OnEnable(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ToolTip t = d as ToolTip;

            DependencyObject parent = t;
            do
            {
                parent = VisualTreeHelper.GetParent(parent);
                if(parent!=null)
                    System.Diagnostics.Debug.Print(parent.GetType().FullName);
            } while (parent != null);

            parent = t;

            do
            {
                //first logical parent is the popup
                parent = LogicalTreeHelper.GetParent(parent);
                if (parent != null)
                    System.Diagnostics.Debug.Print(parent.GetType().FullName);
            } while (parent != null);

        }  
    }
}

xaml

<Button Content="Click me" ToolTip="Likes to be clicked">
    <Button.Resources>
        <Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource {x:Type ToolTip}}" 
               xmlns:l="clr-namespace:CSharpWPF">
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="HasDropShadow" Value="True" />
            <Setter Property="l:ToolTipHelper.IsEnabled" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToolTip}">
                        <StackPanel Background="Wheat" Height="200" Width="200">
                            <TextBlock x:Name="TxbTitle" FontSize="24" Text="ToolTip" Background="BurlyWood" />
                            <ContentPresenter />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Resources>
</Button>

I have added the newly created attached property to tooltip style `<Setter Property="l:ToolTipHelper.IsEnabled" Value="True"/>`

Retrieve ToolTip instance from code behind

In event you can not specify the style or template of style from xaml then code behind is your way to retrieve the tooltip instance

sample code

    Style style = new Style(typeof(ToolTip), (Style)this.FindResource(typeof(ToolTip)));
    style.Setters.Add(new Setter(ToolTipHelper.IsEnabledProperty, true));
    this.Resources.Add(typeof(ToolTip), style);

code above creates a style object for tooltip and adds a setter for `ToolTipHelper.IsEnabledProperty` and inject the same style to the resources of the window

as result the property changed handler `OnEnable` will be invoked in the `ToolTipHelper` class when ever the tooltip is required to be displayed. and the dependency object in the handler will be the actual tooltip instance which you may further manipulate.

Problem

Say I have a `ToolTip` with a style specified in XAML like this: ``` <Button Content="Click me" ToolTip="Likes to be clicked"> <Button.Resources> <Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource {x:Type ToolTip}}"> <Setter Property="OverridesDefaultStyle" Value="true" /> <Setter Property="HasDropShadow" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ToolTip}"> <StackPanel Background="Wheat" Height="200" Width="200"> <TextBlock x:Name="TxbTitle" FontSize="24" Text="ToolTip" Background="BurlyWood" /> <ContentPresenter /> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> </Button.Resources> </Button> ``` Given I have a reference to the `Button` and that the `ToolTip` is showing, how can I find the `Popup` of the `ToolTip` (and later look for its visual children, e.g. `TxbTitle`)? Update: Based on pushpraj's answer I was able to get a hold on the (full) visual tree, and it looks like this: ``` System.Windows.Controls.Primitives.PopupRoot System.Windows.Controls.Decorator System.Windows.Documents.NonLogicalAdornerDecorator System.Windows.Controls.ToolTip System.Windows.Controls.StackPanel System.Windows.Controls.TextBlock (TxbTitle) System.Windows.Controls.ContentPresenter System.Windows.Controls.TextBlock System.Windows.Documents.AdornerLayer ``` Here I can find the `TxbTitle` `TextBlock`. (The logical tree like this:) ``` System.Windows.Controls.Primitives.Popup System.Windows.Controls.ToolTip System.String ``` pushpraj's answer is however based on that I can get hold of the `ToolTip` instance. What I have got is the `Button` only, and `Button.ToolTip` property returns the string `"Likes to be clicked"`, not the `ToolTip` instance. So more specifically, the question is, can I get hold of the `ToolTip` or the `Popup` in some way when all I've got is the `Button`. (Crazy idea: is there some way to enumerate all open `Popup`s?)

Original source