Замена отсутствующей опции TextTrimming "CharacterEllipsis" в Silverlight - PullRequest
2 голосов
/ 25 мая 2011

Silverlight (по крайней мере, начиная с версии 4) не имеет опции CharacterEllipsis для TextTrimming, которая WPF имеет .Это может быть использовано на TextBlock.Это означает, что если недостаточно места для отображения «Это невероятно», я мог бы обрезать до «Это ...», но не до «Это невероятно ...», что мы бы предпочли.

Iхотя мы бы попытались реализовать нашу собственную функцию обрезки текста.В принципе, это не так сложно.Довольно глупый способ - измерить пиксели для строки, сравнить с доступной шириной и манипулировать строкой, обрезая последний символ и добавляя «...» в цикле, пока текст по-прежнему не помещается.Вот пример того, как это может работать:

// Not perfect but good enough for us
private bool AutoTrim(string fullText, TextBlock textBlock, double maxWidth)
{
    double factor = maxWidth / textBlock.ActualWidth;
    if (factor > 1)
        return false;

    int newTextLength = (int)Math.Floor((double)fullText.Length * factor);
    string trimTest;
    do
    {
        trimTest = fullText.Substring(0, newTextLength--);
        textBlock.Text = trimTest + "..."; // problematic...
        factor = maxWidth / textBlock.ActualWidth;
    }
    while (factor < 1 && newTextLength > 0);

    return true;
}

Но выполнение этого в коде позади (или внутри Behavior) приводит к некоторым проблемам: Например, когда мы хотим обновить отображаемый текст и установитьСвойство TextBlock TextBlock1.Text = ..., оно фактически может изменить нашу viewModel, если Text привязан к свойству ViewModel.Другие проблемы возникают, когда мы заметили, что view и viewModel могут работать по какой-то причине (мы заметили это в ListBox).

У вас есть идея, как решить эту проблему хорошим способом?

Ответы [ 4 ]

5 голосов
/ 30 декабря 2011

Robby Ingebretsen's DynamicTextBox делает это, помещая TextBlock в пользовательский элемент управления и измеряя доступный размер. Он соответствует режиму обрезки текста CharacterEllipsis в WPF. Режим WordEllipsis был добавлен в Windows Phone 7 Mango, но это не сильно помогает.

3 голосов
/ 01 июня 2011

Дэн Уолин использовал конвертер до того, как TextTrimming = "WordEllipsis" был добавлен в Silverlight 4. Вы можете найти его здесь: http://weblogs.asp.net/dwahlin/archive/2010/05/05/text-trimming-in-silverlight-4.aspx

1 голос
/ 19 марта 2014

Вот как я обошел отсутствие опции CharacterEllipsis.Мое решение тоже не идеально, но оно до сих пор работало для меня.

Сначала я добавил следующий вспомогательный метод:

public static void AutoTrimTextBlock(TextBlock textBlock, double maxWidth)
{
    if (!string.IsNullOrWhiteSpace(textBlock.Text))
    {
        var currentWidth = textBlock.ActualWidth;
        if (currentWidth > maxWidth)
        {
            if (textBlock.Text.Length > 2)
            {
                int substrLength = textBlock.Text.Length - 1;
                if (textBlock.Text[substrLength] == '…')
                    substrLength--;
                textBlock.Text = textBlock.Text.Substring(0, substrLength) + '…';
            }
            else if (textBlock.Text.Length == 2)
            {
                if (textBlock.Text[1] == '…')
                    textBlock.Text = "…";
                else
                    textBlock.Text = textBlock.Text[0].ToString() + '…';
            }
            else //implies: if (length == 1)
            {
                textBlock.Text = string.Empty;
            }
        }
    }
}

Затем я обновил свой XAML, чтобы он выглядел так:

<Grid x:Name="MyGrid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="Column0" Width="Auto"/>
        <ColumnDefinition x:Name="Column1" Width="*"/>
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0" x:Name="SomeOtherText" Text="{Binding OtherString}"/>

    <TextBlock Grid.Column="1" x:Name="MyTextBlock"
               TextWrapping="NoWrap"                        <!--Disable text wrapping-->
               TextTrimming="None"                          <!--Disable built-in text trimming-->
               Text="{Binding MyString, Mode=OneWay}"       <!--OneWay binding avoids writing trimmed text back to view model-->
               LayoutUpdated="MyTextBlock_LayoutUpdated"/>  <!--LayoutUpdated event will trigger custom text trimming-->
</Grid>

Наконец, в коде я добавил следующее:

void MyTextBlock_LayoutUpdated(object sender, System.EventArgs e)
{
    // Calculate maximum width for MyTextBlock.
    // I did it by checking the parent column width,
    // but you can do it any way you like.
    double maxWidth = Column1.ActualWidth - MyTextBlock.Margin.Left - MyTextBlock.Margin.Right;

    // Start trimming
    AutoTrimTextBlock(MyTextBlock, maxWidth);
}

Результат: при каждом изменении свойства MyString вызывается обработчик события LayoutUpdated и метод AutoTrimTextBlock ()называется.Если MyTextBlock слишком широкий, его свойство Text обрезается и добавляется «…».Это вызывает другое событие LayoutUpdated.Процесс повторяется до тех пор, пока ширина MyTextBlock не станет меньше указанного максимума.

Как я уже сказал, он не идеален и не особенно элегантен, но он хорошо работает в примерах, подобных приведенному выше.

IМне не нравится идея использовать событие LayoutUpdated, но я не смог найти другое подходящее.К сожалению, TextChanged не существует для TextBlock: (

Пожалуйста, дайте мне знать, если я могу что-то улучшить.

0 голосов
/ 18 августа 2014
    private bool TrimExtraCharacters(TextBlock textBlock)
    {
        if (textBlock != null && textBlock.ActualWidth > 0.1 && !string.IsNullOrWhiteSpace(textBlock.Text))
        {
            if (textBlock.ActualWidth > textBlock.MaxWidth)
            {
                textBlock.Text += '…';
                int lastLetterIndex = textBlock.Text.Length -2;
                do
                {
                    textBlock.Text = textBlock.Text.Remove(lastLetterIndex, 1);
                    --lastLetterIndex;
                } while (textBlock.ActualWidth > textBlock.MaxWidth);
            }
            return true;
        }
        return false;
    }
...