¿Cómo puedo determinar si mi texto TextBlock está siendo recortado?

El siguiente textblock se ajusta y recorta según lo esperado. La elipsis “…” se muestra cuando se recorta el texto.

 

Me gustaría mostrar una información sobre herramientas sobre el texto con el texto completo, pero solo si el texto está recortado. No estoy seguro de cómo determinar de manera confiable si se muestra el “…” o no.

¿Cómo puedo determinar si el texto está siendo recortado o no?

No he hecho mucho WPF últimamente, así que no estoy seguro de si esto es lo que estás buscando, pero mira este artículo: Personalización de controles WPF “atentos”: toma 2 . Es un poco complejo, pero parece abordar la misma pregunta que estás haciendo. ACTUALIZACIÓN: el sitio web parece haber desaparecido, pero puede encontrar el artículo en el archivo .

Debido a que el enlace en la respuesta de Alek está caído, encontré una copia en caché del enlace de la máquina de retorno. No puede descargar el código vinculado en el artículo, por lo que aquí hay una versión premontada del código. Hubo uno o dos problemas con los que me encontré tratando de hacerlo funcionar, por lo que este código es ligeramente diferente del código en los ejemplos del artículo.

 using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace TextBlockService { //Based on the project from http://web.archive.org/web/20130316081653/http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/ public static class TextBlockService { static TextBlockService() { // Register for the SizeChanged event on all TextBlocks, even if the event was handled. 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 { //If this function is called before databinding has finished the tooltip will never show. //This invoke defers the calculation of the text trimming till after all current pending databinding //has completed. 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 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 "formattedText.MinWidth > formattedText.MaxTextWidth" 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. return (formattedText.Height > textBlock.ActualHeight || formattedText.MinWidth > formattedText.MaxTextWidth); } } } 
      

La solución anterior no funcionó para mí si TextBlock es parte de un ListBoxItem DataTemplate. Propongo otra solución:

 public class MyTextBlock : System.Windows.Controls.TextBlock { protected override void OnToolTipOpening(WinControls.ToolTipEventArgs e) { if (TextTrimming != TextTrimming.None) { e.Handled = !IsTextTrimmed(); } } private bool IsTextTrimmed() { Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); return ActualWidth < DesiredSize.Width; } } 

XAML:

   

Ampliando la respuesta de Bidy. Esto creará un TextBlock que solo muestra la información sobre herramientas cuando no se muestra todo el texto. La información sobre herramientas se redimensionará a los contenidos (a diferencia de la información sobre herramientas predeterminada que seguirá siendo un cuadro de una línea con el texto cortado).

 using System; using System.Windows; using System.Windows.Controls; namespace Optimizers.App4Sales.LogViewer.Components { public class CustomTextBlock : TextBlock { protected override void OnInitialized(EventArgs e) { // we want a tooltip that resizes to the contents -- a textblock with TextWrapping.Wrap will do that var toolTipTextBlock = new TextBlock(); toolTipTextBlock.TextWrapping = TextWrapping.Wrap; // bind the tooltip text to the current textblock Text binding var binding = GetBindingExpression(TextProperty); if (binding != null) { toolTipTextBlock.SetBinding(TextProperty, binding.ParentBinding); } var toolTipPanel = new StackPanel(); toolTipPanel.Children.Add(toolTipTextBlock); ToolTip = toolTipPanel; base.OnInitialized(e); } protected override void OnToolTipOpening(ToolTipEventArgs e) { if (TextTrimming != TextTrimming.None) { e.Handled = !IsTextTrimmed(); } } private bool IsTextTrimmed() { Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); return ActualWidth < DesiredSize.Width; } } } 

Uso de XAML: