如果文本过长,我该如何自动显示工具提示?

4
在Windows商店应用程序中,我有以下TextBlock:
        <TextBlock Text="Seriously long text for the purpose of showing tooltip"
                   TextTrimming="CharacterEllipsis" />

当文本过长以至于需要省略号(...)显示时,如何自动显示工具提示?

3个回答

6

以下是基于这篇文章这篇回答的解决方案。

首先,创建一个附加属性来启用自动工具提示:

public static class TextBlockUtils {
    public static readonly DependencyProperty AutoTooltipProperty =
        DependencyProperty.RegisterAttached ("AutoTooltip", typeof (bool), typeof (TextBlockUtils),
                                             new PropertyMetadata (false, OnAutoTooltipPropertyChanged));

    public static void SetAutoTooltip (DependencyObject d, bool value) {
        d.SetValue (AutoTooltipProperty, value);
    }

    public static bool GetAutoTooltip (DependencyObject d) {
        return (bool) d.GetValue (AutoTooltipProperty);
    }

    private static void OnAutoTooltipPropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e) {
        var tb = d as TextBlock;
        if (tb != null) {
            bool newValue = (bool) e.NewValue;
            if (newValue) {
                SetTooltipBasedOnTrimmingState (tb);
                tb.SizeChanged += OnTextBlockSizeChanged;
            }
            else {
                tb.SizeChanged -= OnTextBlockSizeChanged;
            }
        }
    }

    private static void OnTextBlockSizeChanged (object sender, SizeChangedEventArgs e) {
        var tb = sender as TextBlock;
        if (tb != null) {
            SetTooltipBasedOnTrimmingState (tb);
        }
    }

    private static void SetTooltipBasedOnTrimmingState (TextBlock tb) {
        bool isTextTrimmed = tb.ActualWidth < tb.DesiredSize.Width;
        ToolTipService.SetToolTip (tb, isTextTrimmed ? tb.Text : null);
    }
}

然后在XAML中像这样使用它:

<TextBlock Content="long text"
           TextTrimming="CharacterEllipsis"
           TextBlockUtils.AutoTooltip="True" />

当文本块被截断时,提示框才会显示。


0
通常情况下,您点击它并打开一个视图,在该视图中,文本会以完整的形式显示出来,这要么是因为它有更多的空间/使用较小的字体,要么是因为文本换行/滚动。

这是一个不错的解决方案,但不适用于我的情况。为了简洁起见,我省略了代码,但我的文本块是按钮的内容,并且点击按钮已经绑定到导航命令。如果文本太长而无法在没有省略号的情况下显示,我确实需要悬停提示。 - Scott Ferguson

0

基于pogosama的回答,我想提出我的两分建议。

当TextBlock被重用时,我必须检测文本更改,因为大小更改是不够的。

此外,这个解决方案处理了ToolTip的模板版本。

关键在于:ToolTipService.SetIsEnabled(tb, isTextTrimmed);

OnTextBlockSizeChanged在两种情况下都被使用,因为OnToolTipTextChanged在之前被调用,因此FormattedText尚未计算。

public static class TextBlockUtils
{
    /// <summary>
    /// Used by the simple version
    /// </summary>
    public static readonly DependencyProperty ToolTipTextProperty =
        DependencyProperty.RegisterAttached("ToolTipText", typeof(string), typeof(TextBlockUtils), new PropertyMetadata(null, OnToolTipTextChanged));
    public static string GetToolTipText(DependencyObject obj) => (string)obj.GetValue(ToolTipTextProperty);
    public static void SetToolTipText(DependencyObject obj, string value) => obj.SetValue(ToolTipTextProperty, value);

    public static readonly DependencyProperty HasSubscribedProperty =
        DependencyProperty.RegisterAttached("HasSubscribed", typeof(bool), typeof(TextBlockUtils), new PropertyMetadata(false, null));
    public static bool GetHasSubscribed(DependencyObject d) => (bool)d.GetValue(HasSubscribedProperty);
    public static void SetHasSubscribed(DependencyObject d, bool value) => d.SetValue(HasSubscribedProperty, value);

    /// <summary>
    /// Used by the templated version
    /// </summary>
    public static readonly DependencyProperty AutoToolTipProperty =
        DependencyProperty.RegisterAttached("AutoToolTip", typeof(bool), typeof(TextBlockUtils), new PropertyMetadata(false, OnAutoToolTipPropertyChanged));
    public static bool GetAutoToolTip(DependencyObject d) => (bool)d.GetValue(AutoToolTipProperty);
    public static void SetAutoToolTip(DependencyObject d, bool value) => d.SetValue(AutoToolTipProperty, value);

    private static void OnToolTipTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextBlock tb = d as TextBlock;

        if (!GetHasSubscribed(tb))//anti multi subscribe
        {
            tb.SizeChanged -= OnTextBlockSizeChanged;
            tb.SizeChanged += OnTextBlockSizeChanged;
            SetHasSubscribed(tb, true);
        }

        SetToolTipBasedOnTrimmingState(tb);
    }

    private static void OnAutoToolTipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tb = d as TextBlock;

        bool newValue = (bool)e.NewValue;
        if (newValue)
        {
            SetToolTipBasedOnTrimmingState(tb);
            tb.SizeChanged += OnTextBlockSizeChanged;
        }
        else
        {
            tb.SizeChanged -= OnTextBlockSizeChanged;
        }
    }

    private static void OnTextBlockSizeChanged(object sender, SizeChangedEventArgs e)
    {
        var tb = sender as TextBlock;
        SetToolTipBasedOnTrimmingState(tb);
    }

    private static void SetToolTipBasedOnTrimmingState(TextBlock tb)
    {
        Typeface typeface = new Typeface(tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch);
        FormattedText formattedText = new FormattedText(tb.Text, System.Threading.Thread.CurrentThread.CurrentCulture, tb.FlowDirection, typeface, tb.FontSize, tb.Foreground) { MaxTextWidth = tb.ActualWidth };

        bool isTextTrimmed = (formattedText.Height > tb.ActualHeight || formattedText.MinWidth > formattedText.MaxTextWidth);

        ToolTipService.SetIsEnabled(tb, isTextTrimmed);//because ToolTipService.ShowOnDisabledProperty = false, this works

        object templatedToolTip = tb.FindName("TemplatedToolTip");
        if (templatedToolTip != null && templatedToolTip is ToolTip)
        {
            ToolTip toolTip = templatedToolTip as ToolTip;
            tb.ToolTip = toolTip;
        }
        else
            tb.ToolTip = GetToolTipText(tb);
    }
}

简单版本

<TextBlock Text={Binding MyText} utils:TextBlockUtils.ToolTipText="{Binding Text, RelativeSource={RelativeSource Self}, Mode=OneWay}" TextTrimming="WordEllipsis">
or
<TextBlock Text={Binding MyText} utils:TextBlockUtils.ToolTipText="{Binding Whatever}" TextTrimming="WordEllipsis">

模板版本

<TextBlock Text="{Binding Comment.CommentText, FallbackValue=Comment}" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" utils:TextBlockUtils.AutoToolTip="True">
    <TextBlock.ToolTip>
        <ToolTip x:Name="TemplatedToolTip" Placement="Bottom">
            <ToolTip.Template>
                <ControlTemplate>
                    <Border>
                        <TextBlock TextWrapping="Wrap">
                            <Run Text="Event :" FontStyle="Italic" FontWeight="Bold"/>
                            <LineBreak/>
                            <Run Text="{Binding Whatever}"/>
                            <LineBreak/>
                            <Run Text="{Binding Comment.CommentText}"/>
                        </TextBlock>
                    </Border>
                </ControlTemplate>
            </ToolTip.Template>
        </ToolTip>
    </TextBlock.ToolTip>
</TextBlock>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接