2

Silverlight(至少,从版本 4 开始)没有.WPFCharacterEllipsis选项。它可以用在. 这意味着,如果没有足够的空间来显示“这太不可思议了”,我可以修剪为“那是……”,而不是我们想要的“那是令人难以置信的……”。TextTrimmingTextBlock

不过,我们会尝试实现我们的自定义文本修剪功能。基本上,这并不难。一种非常愚蠢的方法是测量字符串的像素,与可用宽度进行比较,然后通过剪切最后一个字符并在文本仍然不适合时在循环中添加“...”来操作字符串。这是一个如何工作的示例:

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

但是在代码后面(或在 a 中Behavior)这样做会导致一些问题:例如,当我们想要更新显示的文本并设置 TextBlock 的TextBlock1.Text = ...属性时,如果 Text 绑定到 ViewModel 属性,它实际上可能会更改我们的 viewModel。当我们注意到 view 和 viewModel 可能出于某种原因运行不同步时,会出现另一个问题(我们注意到在 ListBox 中)。

您对如何以一种好的方式解决这个问题有更好的想法吗?

4

4 回答 4

5

Robby Ingebretsen 的DynamicTextBox通过将 TextBlock 包装在自定义控件中并测量可用大小来做到这一点。它匹配 WPF 的 CharacterEllipsis 文本修剪模式。WordEllipsis 模式确实被添加到 Windows Phone 7 Mango 中,但这在这里没有多大帮助。

于 2011-12-29T23:05:14.940 回答
3

在将 TextTrimming="WordEllipsis" 添加到 Silverlight 4 之前,Dan Wahlin 使用了转换器。您可以在此处找到它:http ://weblogs.asp.net/dwahlin/archive/2010/05/05/text-trimming-in-silverlight -4.aspx

于 2011-06-01T06:51:55.160 回答
1

这是我解决缺少 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 的宽度小于指定的最大值。

正如我所说,它并不完美,也不是特别优雅,但在上述示例中它可以正常工作。

我不喜欢使用 LayoutUpdated 事件的想法,但我找不到另一个合适的。不幸的是,TextBlock 不存在 TextChanged :(

如果有什么我可以改进的,请告诉我。

于 2014-03-19T05:23:45.847 回答
0
    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;
    }
于 2014-08-18T18:59:24.187 回答