У меня есть GridItem с фиксированной высотой/шириной.
Он содержит текстовый блок с максимальным набором строк.
Как я могу определить, обрезан ли этот текст? Я хочу добавить специальный функционал, если он будет обрезан.
У меня есть GridItem с фиксированной высотой/шириной.
Он содержит текстовый блок с максимальным набором строк.
Как я могу определить, обрезан ли этот текст? Я хочу добавить специальный функционал, если он будет обрезан.
Старый способ — когда для TextWrapping установлено значение None
Чтобы узнать, обрезан ли TextBlock
, мы можем подписаться на его событие SizeChanged
и сравнить его ActualWidth
с указанным вами MaxWidth
. Чтобы получить справа ActualWidth
от TextBlock
, нам нужно оставить для TextTrimming
значение по умолчанию (т. е. TextTrimming.None
) и настроить его на обрезание, как только ширина превысит ширину.
Новый способ — когда TextWrapping установлен на Wrap
Теперь, когда я знаю, поскольку TextWrapping
установлено на Wrap
и предполагается, что VirticalAlignment
не указано (по умолчанию Stretch
), Width
всегда будет оставаться неизменным. Нам нужно только отслеживать событие SizeChanged
, когда фактическая высота TextBlock
превышает высоту его родителя.
Давайте используем Behavior
для инкапсуляции всей вышеописанной логики. Здесь следует упомянуть, что вспомогательный класс static
с набором присоединенных свойств или новый элемент управления, унаследованный от TextBlock
, может делать то же самое; но, будучи большим поклонником Blend, я предпочитаю использовать Behaviors
, когда это возможно.
Поведение
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;
}
}
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>
Обратите внимание, что Behavior
предоставляет свойство зависимости IsTrimmed
, вы можете привязать его данные к свойству в вашей модели представления (т.е. IsTrimmedInVm
в данном случае).
P.S. В WinRT нет функции FormattedText
, иначе реализация могла бы немного отличаться.
MaxWidth
. Поскольку TextBlock
растягивается по горизонтали и вертикали, его ширина останется прежней. Высота изменится только тогда, когда она превысит родительскую высоту. Итак, все, что нам нужно сделать, это прослушать событие SizeChanged
и сделать что-то, когда высота превысит допустимый предел. Я обновил behavior
, а также добавил TextWrapping
в xaml. Теперь он должен работать на любом количестве строк.
- person Justin XL; 09.09.2014
В итоге мы сделали статическую функцию
// 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;
}
Хитрость заключается в том, чтобы убедиться, что Maxlines и обрезка текста НЕ установлены в текстовом блоке до запуска этой функции. После того, как эта функция вернется, то есть когда будут установлены Maxlines. В моем случае я просто сохранил возвращенное логическое значение в содержащем объекте, поэтому знал, что оно длиннее. Затем я устанавливаю maxlines и еще одну кнопку, чтобы увидеть расширенный контент на основе этого логического значения.