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.
Cura di spiegare perché la mia soluzione non funziona? IMHO, il mio è meglio. –
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. –