2014-08-29 20 views

risposta

1

Abbiamo finito per fare una funzione statica

// Ensure block does not have MAXLINES or text trimming set prior to checking 
    public static bool IsTruncated(TextBlock block, int maxLines) 
    { 
     if (block == null) 
     { 
      throw new ArgumentNullException("block"); 
     } 

     //the cut-off height is the height at which text will be cut off in the UI 
     var cutOffHeight = maxLines * block.LineHeight; 

     //determine whether the actual height of the TextBlock is greater than the cut-off height 
     return block.ActualHeight > cutOffHeight; 
    } 

Il trucco è quello di assicurarsi che maxLines e rifilatura di testo non è impostato sul blocco di testo prima di eseguire questa funzione. Dopo che questa funzione è tornata, è quando si impostano le Maxlines. Nel mio caso ho appena salvato il booleano restituito in un oggetto contenitore, quindi sapevo che era più lungo. Poi ho impostato le maxline e un altro pulsante per vedere il contenuto esteso basato su quello booleano.

+1

Cura di spiegare perché la mia soluzione non funziona? IMHO, il mio è meglio. –

+0

Non ho detto che il tuo non ha funzionato. Ho appena pubblicato la soluzione con cui siamo effettivamente andati. Oltre al fatto che la nostra soluzione è più corta, stiamo evitando l'associazione dei dati che era il problema principale. Apprezzo la tua risposta e l'abbiamo svalutata più volte. –

5

Old Way - quando TextWrapping è impostata su Nessuno

Per sapere se un TextBlock viene tagliato, possiamo sottoscrivere l'evento SizeChanged e confrontare il suo ActualWidth al MaxWidth specificato. Per ottenere a destraActualWidth dello TextBlock, sarà necessario lasciare TextTrimming al valore predefinito (ad esempio TextTrimming.None) e impostarlo in modo che venga tagliato una volta che la larghezza è passata.

nuovo modo - quando TextWrapping è impostato su Wrap

Ora che lo so perché l'TextWrapping è impostato su Wrap e assumere la VirticalAlignment non è specificato (default a Stretch), il Width rimarrà sempre lo stesso . Dobbiamo solo monitorare l'evento SizeChanged quando l'altezza effettiva di TextBlock supera l'altezza del suo genitore.

Utilizziamo uno Behavior per incapsulare tutta la logica di cui sopra. Quello che deve essere menzionato qui è che una classe helper static con un gruppo di proprietà collegate o un nuovo controllo che eredita da TextBlock può fare esattamente la stessa cosa; ma essendo un grande fan di Blend, preferisco usare Behaviors quando possibile.

Il comportamento

public class TextBlockAutoTrimBehavior : DependencyObject, IBehavior 
{ 
    public bool IsTrimmed 
    { 
     get { return (bool)GetValue(IsTrimmedProperty); } 
     set { SetValue(IsTrimmedProperty, value); } 
    } 

    public static readonly DependencyProperty IsTrimmedProperty = 
     DependencyProperty.Register("IsTrimmed", typeof(bool), typeof(TextBlockAutoTrimBehavior), new PropertyMetadata(false)); 

    public DependencyObject AssociatedObject { get; set; } 

    public void Attach(DependencyObject associatedObject) 
    { 
     this.AssociatedObject = associatedObject; 
     var textBlock = (TextBlock)this.AssociatedObject; 

     // subscribe to the SizeChanged event so we will know when the Width of the TextBlock goes over the MaxWidth 
     textBlock.SizeChanged += TextBlock_SizeChanged; 
    } 

    private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     // ignore the first time height change 
     if (e.PreviousSize.Height != 0) 
     { 
      var textBlock = (TextBlock)sender; 

      // notify the IsTrimmed dp so your viewmodel property will be notified via data binding 
      this.IsTrimmed = true; 
      // unsubscribe the event as we don't need it anymore 
      textBlock.SizeChanged -= TextBlock_SizeChanged; 

      // then we trim the TextBlock 
      textBlock.TextTrimming = TextTrimming.WordEllipsis; 
     } 
    } 

    public void Detach() 
    { 
     var textBlock = (TextBlock)this.AssociatedObject; 
     textBlock.SizeChanged += TextBlock_SizeChanged; 
    } 
} 

Il XAML

<Grid HorizontalAlignment="Center" Height="73" VerticalAlignment="Center" Width="200" Background="#FFD2A6A6" Margin="628,329,538,366"> 
    <TextBlock x:Name="MyTextBlock" TextWrapping="Wrap" Text="test" FontSize="29.333"> 
     <Interactivity:Interaction.Behaviors> 
      <local:TextBlockAutoTrimBehavior IsTrimmed="{Binding IsTrimmedInVm}" /> 
     </Interactivity:Interaction.Behaviors> 
    </TextBlock> 
</Grid> 

Si noti che il Behavior espone una proprietà di dipendenza IsTrimmed, è possibile i dati associarlo a una proprietà nel ViewModel (cioè IsTrimmedInVm in questo caso).

P.S. Non c'è la funzione FormattedText in WinRT altrimenti l'implementazione potrebbe essere leggermente diversa.

+0

La larghezza tiene conto anche dell'altezza? Significato se la mia casella di larghezza 100 è alta 2 righe, la larghezza di quel testo ora è 200? –

+0

Oh, se questo è il caso, è ancora più semplice.In realtà non abbiamo più bisogno di 'MaxWidth'. Dato che 'TextBlock' è allungato orizzontalmente e verticalmente, la sua larghezza rimarrà invariata. L'altezza cambierà solo quando supererà la sua altezza genitore. Quindi tutto ciò che dobbiamo fare è ascoltare l'evento 'SizeChanged' e fare cose quando l'altezza va oltre. Ho aggiornato il 'comportamento' e aggiunto' TextWrapping' allo xaml. Ora dovrebbe funzionare su qualsiasi numero di linee. –

Problemi correlati