如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; using System.Windows; using System.Globalization; namespace XXXX { public class TooltipTextBlock : TextBlock { static TooltipTextBlock() { OneLineHeightProperty = DependencyProperty.Register( "OneLineHeight", typeof(double), typeof(TooltipTextBlock), new FrameworkPropertyMetadata((double)16) ); } protected override void OnToolTipOpening(ToolTipEventArgs e) { if (TextTrimming != TextTrimming.None) { e.Handled = !IsTextTrimmed(); } } private bool IsTextTrimmed() { var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch); var formattedText = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection, typeface, FontSize, Foreground); double lineHeight = OneLineHeight;//formattedText.Height; double totalWidth = formattedText.Width; int lines = (int)Math.Ceiling(totalWidth / ActualWidth); return (lines * lineHeight > MaxHeight); } public double OneLineHeight { get { return (double)GetValue(OneLineHeightProperty); } set { SetValue(OneLineHeightProperty, value); } } public static readonly DependencyProperty OneLineHeightProperty; } }
使用:
TooltipTextBlock tb = new TooltipTextBlock(); tb.Margin = new Thickness(0, 23, 0, 0); tb.Width = 280; tb.MaxHeight = 97; tb.TextAlignment = TextAlignment.Center; tb.Style = (Style)Utils.CommonFunctions.LoadResource("CardBody_TextStyle"); tb.TextTrimming = TextTrimming.WordEllipsis; tb.TextWrapping = TextWrapping.Wrap; tb.OneLineHeight = 24; ToolTip tt = new ToolTip() { Content = des, }; tb.ToolTip = tt;
或:
xmlns:local="clr-namespace:Test"
<local:TooltipTextBlock Text="This is some text lafsdk jflklakjsd " TextWrapping="Wrap" TextTrimming="WordEllipsis" ToolTip="{Binding Text,RelativeSource={RelativeSource Self}}" MaxWidth="80" Height="80" MaxHeight="80" Background="Gray" OneLineHeight="50"/>
新方法:
<TextBlock Text="Demo" ui:TextBlockAutoToolTip.Enabled="True"/>
var textBlock = new TextBlock { Text = "Demo" }; TextBlockAutoToolTip.SetEnabled(textBlock, true);
using System; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; namespace Unclassified.UI { /// <summary> /// Shows a ToolTip over a TextBlock when its text is trimmed. /// </summary> public class TextBlockAutoToolTip { /// <summary> /// The Enabled attached property. /// </summary> public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached( "Enabled", typeof(bool), typeof(TextBlockAutoToolTip), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnAutoToolTipEnabledChanged))); /// <summary> /// Sets the Enabled attached property on a TextBlock control. /// </summary> /// <param name="dependencyObject">The TextBlock control.</param> /// <param name="enabled">The value.</param> public static void SetEnabled(DependencyObject dependencyObject, bool enabled) { dependencyObject.SetValue(EnabledProperty, enabled); } private static readonly TrimmedTextBlockVisibilityConverter ttbvc = new TrimmedTextBlockVisibilityConverter(); private static void OnAutoToolTipEnabledChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) { TextBlock textBlock = dependencyObject as TextBlock; if (textBlock != null) { bool enabled = (bool)args.NewValue; if (enabled) { var toolTip = new ToolTip { Placement = System.Windows.Controls.Primitives.PlacementMode.Relative, VerticalOffset = -3, HorizontalOffset = -5, Padding = new Thickness(4, 2, 4, 2), Background = Brushes.White }; toolTip.SetBinding(UIElement.VisibilityProperty, new System.Windows.Data.Binding { RelativeSource = new System.Windows.Data.RelativeSource(System.Windows.Data.RelativeSourceMode.Self), Path = new PropertyPath("PlacementTarget"), Converter = ttbvc }); toolTip.SetBinding(ContentControl.ContentProperty, new System.Windows.Data.Binding { RelativeSource = new System.Windows.Data.RelativeSource(System.Windows.Data.RelativeSourceMode.Self), Path = new PropertyPath("PlacementTarget.Text") }); toolTip.SetBinding(Control.ForegroundProperty, new System.Windows.Data.Binding { RelativeSource = new System.Windows.Data.RelativeSource(System.Windows.Data.RelativeSourceMode.Self), Path = new PropertyPath("PlacementTarget.Foreground") }); textBlock.ToolTip = toolTip; textBlock.TextTrimming = TextTrimming.CharacterEllipsis; } } } private class TrimmedTextBlockVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var textBlock = value as TextBlock; if (textBlock == null) return Visibility.Collapsed; Typeface typeface = new Typeface( textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch); // FormattedText is used to measure the whole width of the text held up by TextBlock container FormattedText formattedText = new FormattedText( textBlock.Text, System.Threading.Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground); formattedText.MaxTextWidth = textBlock.ActualWidth; // When the maximum text width of the FormattedText instance is set to the actual // width of the textBlock, if the textBlock is being trimmed to fit then the formatted // text will report a larger height than the textBlock. Should work whether the // textBlock is single or multi-line. // The width check detects if any single line is too long to fit within the text area, // this can only happen if there is a long span of text with no spaces. bool isTrimmed = formattedText.Height > textBlock.ActualHeight || formattedText.MinWidth > formattedText.MaxTextWidth; return isTrimmed ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } }