7
votes

I have developed a WPF sample project.

Here is the main Window's XAML markup :

<Window x:Class="ToolTipSample.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"
        WindowState="Maximized">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Button Click="OnButtonClick">Show ToolTip</Button>

        <StatusBar Grid.Row="2">
            <StatusBarItem>
                <TextBlock Text="TextBlock With ToolTip">
                    <TextBlock.ToolTip>
                        <ToolTip x:Name="m_toolTip">
                            ToolTip
                        </ToolTip>
                    </TextBlock.ToolTip>
                </TextBlock>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

Here is the main Window's code-behind without the using statements :

namespace ToolTipSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OnButtonClick(object p_sender, RoutedEventArgs p_args)
        {
            m_toolTip.IsOpen = true;
        }
    }
}

I want to programmatically show the ToolTip when the Button is clicked.
I want the ToolTip to be shown above its TextBlock parent.

The ToolTip is automatically shown when the mouse cursor is over the TextBlock and during a constant amount of time C approximatively equal to 5 seconds.
I want the ToolTip to be shown during C when the Button is clicked.

My goals are not achieved in the current project.
The ToolTip is shown when the Button is clicked :

enter image description here

But :

  • The ToolTip is too far from its TextBlock parent.
  • The ToolTip is not automatically hidden

What do I have to do to achieve my goals ?
Any help will be greatly appreciated.

2

2 Answers

8
votes

You have a number of problems. The first and simplest to fix is that you are only opening and not closing the ToolTip. You said I want the ToolTip to be shown during the same amount of time when the Button is clicked, and this is easily implemented handling the PreviewMouseDown and PreviewMouseUp events:

private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    m_toolTip.PlacementTarget = PlacementTarget;
    m_toolTip.IsOpen = true;
}

private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    m_toolTip.IsOpen = false;
}

...

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Button PreviewMouseDown="Button_PreviewMouseDown" 
        PreviewMouseUp="Button_PreviewMouseUp">Show ToolTip</Button>
    <StatusBar Grid.Row="2">
        <StatusBarItem>
            <TextBlock Name="PlacementTarget" Text="TextBlock With ToolTip">
                <TextBlock.ToolTip>
                    <ToolTip x:Name="m_toolTip" Placement="Top" HorizontalOffset="50" 
                        VerticalOffset="-5">ToolTip</ToolTip>
                </TextBlock.ToolTip>
            </TextBlock>
        </StatusBarItem>
    </StatusBar>
</Grid>

Your other problem is slightly more tricky to fix... it seems to me as though there may be some bug involved in the positioning of your ToolTip. Normally, despite what @icebat said, it is possible to alter the position of a ToolTip using the ToolTip.Placement property. This can be set to one of the PlacementMode Enumerations.

The default value is Mouse and this is the definition from the linked page on MSDN:

A postion of the Popup control that aligns its upper edge with the lower edge of the bounding box of the mouse and aligns its left edge with the left edge of the bounding box of the mouse. If the lower screen-edge obscures the Popup, it repositions itself to align with the upper edge of the bounding box of the mouse. If the upper screen-edge obscures the Popup, the control repositions itself to align with the upper screen-edge.

This explains why the ToolTip is displayed far from the TextBlock placement target... because the Button and therefore the mouse (when clicking) is far from the TextBlock. However, by setting the Placement property to another value should enable a wide range of positions to be achieved. However, setting different values of the Placement property alone, will just display the ToolTip in the top left corner of the screen.

To address this situation, you should also set the ToolTip.PlacementTarget Property, as @icebat correctly noted in the comment, but apparently only from code. Once the PlacementTarget property has been set, the Placement property value works as expected. From this linked page:

You can position a ToolTip by setting the PlacementTarget, PlacementRectangle, Placement, HorizontalOffset, and VerticalOffsetProperty properties.

enter image description here

4
votes

I have achieved my goals.
Sheridan's answer and comments help me.
I have updated my sample project.
The ToolTip is now shown just above the TextBlock when the Button is clicked.
And a Timer's callback method closes the ToolTip after a constant amount of time equal to 2500 ms.

Here is the updated main Window's XAML markup :

<Window x:Class="ToolTipSample.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"
        WindowState="Maximized">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Button Click="OnButtonClick">Show ToolTip</Button>

        <StatusBar Grid.Row="2">
            <StatusBarItem>
                <TextBlock Width="900" />
            </StatusBarItem>
            <StatusBarItem>
                <TextBlock x:Name="m_statusMessage" Text="TextBlock With ToolTip" ToolTipService.ShowDuration="30000">
                    <TextBlock.ToolTip>
                        <ToolTip x:Name="m_toolTip" Placement="Top">
                            <TextBlock>
                                ToolTip ToolTipToolTipToolTipToolTipToo lTipToolTipToolTipT oolTipToolTipT
                                <LineBreak />
                                oolTipToolTi pToolTipToo lTipToolTipToolTipToolTipToolTipTo olTipToolTipToolTipTool
                                <LineBreak />
                                TipToo lTipToolTipToolTipToo lTipToolTipTo olTipToolTip
                            </TextBlock>
                        </ToolTip>
                    </TextBlock.ToolTip>
                </TextBlock>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

Here is the updated main Window's code-behind without the using statements :

namespace ToolTipSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Timer m_toolTipClosingTimer;

        public MainWindow()
        {
            InitializeComponent();
            m_toolTipClosingTimer = new Timer(ToolTipClosingCallBack, null, Timeout.Infinite, Timeout.Infinite);
        }

        private void OnButtonClick(object p_sender, RoutedEventArgs p_args)
        {
            m_toolTip.PlacementTarget = m_statusMessage;
            m_toolTip.IsOpen = true;
            m_toolTipClosingTimer.Change(2500, Timeout.Infinite);
        }

        private void ToolTipClosingCallBack(object p_useless)
        {
            Dispatcher.Invoke(() =>
                {
                    m_toolTip.IsOpen = false;
                });
        }
    }
}