Erofh Tor
Erofh Tor

Reputation: 159

WPF: how to auto show my ListView ToolTip when focus

So i have ListViewItem with my object:

public class ClipboardItem : INotifyPropertyChanged
{
    private string _text { get; set; }
    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            NotifyPropertyChanged();
        }
    }

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

And ToolTip and i want when my ListViewItem IsSelected=True to show my ToolTip

This is my ListViewItem CellTemplate:

                                                <TextBlock Text="{Binding Path=Text}"
                                                           Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
                                                           Grid.Column="1"
                                                           Margin="5,0,0,0">
                                                    <TextBlock.ToolTip>
                                                        <ToolTip Content="{Binding Path=Text}"
                                                                 Placement="Left" 
                                                                 PlacementRectangle="0,0,0,0"
                                                                 HorizontalOffset="10" 
                                                                 VerticalOffset="20"
                                                                 HasDropShadow="false"/>
                                                    </TextBlock.ToolTip>
                                                </TextBlock>

When i move over my ListViewItem with my Up & Down arrows i want to auto show my TooTip and not only when MouseIsOver

i also try to dso it in my ListViewItem style:

    <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False" />
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
        </MultiDataTrigger.Conditions>
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="Silver"/>
        <Setter Property="BorderThickness" Value="0.5"/>
        <Setter Property="ToolTip" Value="{Binding Path=Text}"/>
    </MultiDataTrigger>

Non of them works and i can see my ToolTip only when MouseIsOver

Upvotes: 0

Views: 350

Answers (1)

Mark Feldman
Mark Feldman

Reputation: 16119

In general this is a really bad idea. ToolTips have a very specific behavior, which is why WPF doesn't expose it as conveniently as WinForms did with ToolTip.Show. The correct thing to use here would be an adorner.

That said, if you are absolutely adamant about forcibly showing a ToolTip manually then it can be done with a behavior, but you're going to have to fudge some of the functionality that's normally taken care of for you:

using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace YourApp.Behaviors
{
    public class ToolTipBehavior : Behavior<FrameworkElement>
    {
        private ToolTip CurrentToolTip;

        public ListViewItem ListViewItem
        {
            get { return (ListViewItem)GetValue(ListViewItemProperty); }
            set { SetValue(ListViewItemProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ListViewItem.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ListViewItemProperty =
            DependencyProperty.Register("ListViewItem", typeof(ListViewItem), typeof(ToolTipBehavior),
                new PropertyMetadata(null, (d, e) => (d as ToolTipBehavior)?.OnListViewItemChanged(e)));

        private void OnListViewItemChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue is ListViewItem)
                (e.OldValue as ListViewItem).Selected -= ToolTipBehavior_Selected;
            if (e.NewValue is ListViewItem)
                (e.NewValue as ListViewItem).Selected += ToolTipBehavior_Selected;
        }

        private void ToolTipBehavior_Selected(object sender, RoutedEventArgs e)
        {
            if (e.Source != e.OriginalSource)
                return;
            if ((this.ListViewItem != null) && this.ListViewItem.IsSelected)
            {
                var tooltip = this.AssociatedObject.ToolTip as ToolTip;
                if (tooltip != null)
                {
                    if (this.CurrentToolTip != tooltip)
                    {
                        if (this.CurrentToolTip != null)
                            this.CurrentToolTip.Opened -= Tooltip_Opened;
                        this.CurrentToolTip = tooltip;
                        if (this.CurrentToolTip != null)
                            this.CurrentToolTip.Opened += Tooltip_Opened;
                    }
                    this.CurrentToolTip.PlacementTarget = this.AssociatedObject;
                    this.CurrentToolTip.IsOpen = true;
                }
            }
        }

        private async void Tooltip_Opened(object sender, RoutedEventArgs e)
        {
            await Task.Delay(1000);
            (this.AssociatedObject.ToolTip as ToolTip).IsOpen = false;
        }
    }
}

Which you would then use like this:

                <TextBlock Text="{Binding Path=Text}"
                    Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
                    Grid.Column="1"
                    Margin="5,0,0,0">

                    <i:Interaction.Behaviors>
                        <behaviors:ToolTipBehavior ListViewItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" />
                    </i:Interaction.Behaviors>

                    <TextBlock.ToolTip>
                        <ToolTip Content="{Binding Path=Text}" ToolTipService.ShowDuration="2"

                        ...etc...

Upvotes: 1

Related Questions