基于pogosama的回答,我想提出我的两分建议。
当TextBlock被重用时,我必须检测文本更改,因为大小更改是不够的。
此外,这个解决方案处理了ToolTip的模板版本。
关键在于:ToolTipService.SetIsEnabled(tb, isTextTrimmed);
OnTextBlockSizeChanged
在两种情况下都被使用,因为OnToolTipTextChanged
在之前被调用,因此FormattedText
尚未计算。
public static class TextBlockUtils
{
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);
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))
{
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);
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>