因为Alek的回答中的链接已经失效了,我在wayback机器上找到了
缓存的链接。你无法下载文章中链接的代码,所以这里提供了一个预先组装好的版本。在尝试使其工作时,我遇到了一两个问题,因此这个代码与文章中的示例略有不同。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace TextBlockService
{
public static class TextBlockService
{
static TextBlockService()
{
EventManager.RegisterClassHandler(
typeof(TextBlock),
FrameworkElement.SizeChangedEvent,
new SizeChangedEventHandler(OnTextBlockSizeChanged),
true);
}
private static readonly DependencyPropertyKey IsTextTrimmedKey = DependencyProperty.RegisterAttachedReadOnly("IsTextTrimmed",
typeof(bool),
typeof(TextBlockService),
new PropertyMetadata(false));
public static readonly DependencyProperty IsTextTrimmedProperty = IsTextTrimmedKey.DependencyProperty;
[AttachedPropertyBrowsableForType(typeof(TextBlock))]
public static Boolean GetIsTextTrimmed(TextBlock target)
{
return (Boolean)target.GetValue(IsTextTrimmedProperty);
}
public static readonly DependencyProperty AutomaticToolTipEnabledProperty = DependencyProperty.RegisterAttached(
"AutomaticToolTipEnabled",
typeof(bool),
typeof(TextBlockService),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
[AttachedPropertyBrowsableForType(typeof(DependencyObject))]
public static Boolean GetAutomaticToolTipEnabled(DependencyObject element)
{
if (null == element)
{
throw new ArgumentNullException("element");
}
return (bool)element.GetValue(AutomaticToolTipEnabledProperty);
}
public static void SetAutomaticToolTipEnabled(DependencyObject element, bool value)
{
if (null == element)
{
throw new ArgumentNullException("element");
}
element.SetValue(AutomaticToolTipEnabledProperty, value);
}
private static void OnTextBlockSizeChanged(object sender, SizeChangedEventArgs e)
{
TriggerTextRecalculation(sender);
}
private static void TriggerTextRecalculation(object sender)
{
var textBlock = sender as TextBlock;
if (null == textBlock)
{
return;
}
if (TextTrimming.None == textBlock.TextTrimming)
{
textBlock.SetValue(IsTextTrimmedKey, false);
}
else
{
var isTextTrimmed = textBlock.Dispatcher.Invoke(() => CalculateIsTextTrimmed(textBlock), DispatcherPriority.DataBind);
textBlock.SetValue(IsTextTrimmedKey, isTextTrimmed);
}
}
private static bool CalculateIsTextTrimmed(TextBlock textBlock)
{
if (!textBlock.IsArrangeValid)
{
return GetIsTextTrimmed(textBlock);
}
Typeface typeface = new Typeface(
textBlock.FontFamily,
textBlock.FontStyle,
textBlock.FontWeight,
textBlock.FontStretch);
FormattedText formattedText = new FormattedText(
textBlock.Text,
System.Threading.Thread.CurrentThread.CurrentCulture,
textBlock.FlowDirection,
typeface,
textBlock.FontSize,
textBlock.Foreground);
formattedText.MaxTextWidth = textBlock.ActualWidth;
return (formattedText.Height > textBlock.ActualHeight || formattedText.MinWidth > formattedText.MaxTextWidth);
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tbs="clr-namespace:TextBlockService">
<!--
Rather than forcing *all* TextBlocks to adopt TextBlockService styles,
using x:Key allows a more friendly opt-in model.
-->
<Style TargetType="TextBlock" x:Key="TextBlockService">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="tbs:TextBlockService.AutomaticToolTipEnabled" Value="True" />
<Condition Property="tbs:TextBlockService.IsTextTrimmed" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Text}" />
</MultiTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
AutomaticToolTipEnabled
启用它。(响应于代码注释“与其强制所有TextBlock采用TextBlockService样式, 使用x:Key可以采用更友好的选择模型。”) - Kelly EltonformattedText.Height
始终比textBlock.ActualHeight
大 0.04。换句话说,单行的formattedText.Height - textBlock.ActualHeight
等于 0.04,两行时则为 0.08。 - huang