TextBlock 重写,当文本过长时,自动截断文本并出现Tooltip

如下:

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();
            }
        }
    }
}
原文地址:https://www.cnblogs.com/lopengye/p/7754661.html