XAML 如果文本太长,如何自动显示工具提示?

lbsnaicq  于 2023-02-20  发布在  其他
关注(0)|答案(3)|浏览(138)

在Windows应用商店应用程序中,我有以下TextBlock:

<TextBlock Text="Seriously long text for the purpose of showing tooltip"
                   TextTrimming="CharacterEllipsis" />

如果文本太长,没有省略号就无法显示,如何自动显示工具提示?

clj7thdc

clj7thdc1#

这是我的解决方案,基于thisthis
首先,创建一个附加属性以启用自动工具提示:

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" />

工具提示只会在文本块被修剪时显示。

txu3uszq

txu3uszq2#

通常你点击它,打开一个视图,它会完整地显示出来,要么是因为它有更多的空间/使用更小的字体,要么是文本换行/滚动。

cld4siwp

cld4siwp3#

以下是我基于pogosama回答的两点看法。
当重用TextBlock时,我必须检测文本更改,因为大小更改是不够的。
关键是: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>

相关问题