2009-06-25 15 views
31

Il seguente blocco di testo esegue il wrapping e taglia come previsto. L'elisis "..." viene visualizzato quando il testo viene tagliato.Come posso determinare se il mio testo TextBlock viene tagliato?

<TextBlock 
    MaxWidth="60" 
    MaxHeight="60" 
    Text="This is some long text which I would like to wrap." 
    TextWrapping="Wrap" 
    TextTrimming="CharacterEllipsis" /> 

vorrei visualizzare la descrizione sopra il testo con il testo integrale, ma solo se il testo viene tagliato. Non sono sicuro di come determinare in modo affidabile se il "..." viene mostrato o meno.

Come determinare se il testo viene tagliato o no?

+4

domanda perfettamente affermato - bella. :) –

risposta

9

Ultimamente non ho eseguito molti WPF, quindi non sono sicuro se questo è ciò che stai cercando, ma controlla questo articolo: Customizing “lookful” WPF controls – Take 2. È un po 'complesso, ma sembra affrontare la stessa domanda che stai chiedendo. AGGIORNAMENTO: il sito Web sembra sparito, ma è possibile trovare l'articolo nello archive.

+0

L'algoritmo menzionato nell'articolo sopra è esattamente quello che stavo cercando - grazie! –

+2

Il collegamento è morto :( – l33t

+2

@ l33t Avevo anche bisogno del collegamento, [qui è una copia della pagina] (http://web.archive.org/web/20130316081653/http://tranxcoder.wordpress.com/ 2008/10/12/customizing-lookful-wpf-controls-take-2 /) memorizzato nella cache dalla Wayback Machine. –

18

Poiché il collegamento nella risposta di Alek è inattivo, ho trovato un cached copy of the link dalla macchina del wayback. Non è possibile scaricare il codice collegato nell'articolo, quindi ecco una versione pre-assemblata del codice. C'erano uno o due problemi a cui mi sono imbattuto mentre cercavo di farlo funzionare, quindi questo codice è leggermente diverso dal codice negli esempi nell'articolo.

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); 
     } 

    } 
} 
<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> 
+0

Good ups utilizzando la Wayback Machine in quel modo. Continuo a dimenticare che quella cosa è là fuori. – MarqueIV

+0

È già 'Opt-In' perché devi abilitarlo con 'AutomaticToolTipEnabled'. (In risposta al commento di codice 'Invece di forzare * tutti * TextBlocks per adottare gli stili TextBlockService, usando x: Key consente un modello opt-in più amichevole ') –

+0

@KellyElton Non volevo inserire trigger non necessari su ogni TextBlock nella finestra.Potresti semplicemente applicarlo a ogni casella di testo se trovi che non causa alcun sovraccarico. L'app per cui era stata scritta era un'app di immissione dati con una tabella con celle modificabili, che sommava a poche centinaia di caselle di testo. –

2

La soluzione di cui sopra non ha funzionato per me se TextBlock è parte di un ListBoxItem DataTemplate. propongo un'altra soluzione:

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:

<MyTextBlock Text="{Binding Text}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Text}" /> 
+0

Questa è una bella soluzione pulita. Tuttavia non ha funzionato per me: il mio TextBlock viene tagliato (vedo i puntini di sospensione), ma il mio DesiredSize.Width è uguale a ActualWidth. – thehelix

0

Ampliando la risposta di bidy. Questo creerà un TextBlock che mostra solo la descrizione quando non viene mostrato tutto il testo. Il tooltip verrà ridimensionato al contenuto (diversamente dal tooltip di default che rimarrà una casella di una riga con il testo troncato).

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; 
     } 
    } 
} 

utilizzo XAML:

<Window ... 
     xmlns:components="clr-namespace:MyComponents" 
    ... > 

    <components:CustomTextBlock Text="{Binding Details}" TextTrimming="CharacterEllipsis" /> 
Problemi correlati