【问题标题】:Replacement for missing TextTrimming option "CharacterEllipsis" in Silverlight替换 Silverlight 中缺少的 TextTrimming 选项“CharacterEllipsis”
【发布时间】:2011-09-01 21:35:44
【问题描述】:

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

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

// 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,如果文本绑定到 ViewModel 属性。当我们注意到 view 和 viewModel 可能出于某种原因运行不同步时,另一个问题出现了(我们注意到在 ListBox 中)。

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

【问题讨论】:

    标签: silverlight silverlight-4.0 texttrimming


    【解决方案1】:

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

    【讨论】:

    • 酷!我发现只有一个关于性能的问题——它将原始字符串减少 1 个字符,直到达到所需的长度——对于长字符串来说,它非常慢。查看代码,我想到我们可以在期望的字符串长度和期望的字符串长度之间有一个粗略的比率。这是我的更改(抱歉 - 评论不能是代码格式,所有这些对于一条评论来说都太长了):
    • ... 倍率 = 环绕? textSize.Height / (availableSize.Height == 0 ? 1 : availableSize.Height) : textSize.Width / (availableSize.Width == 0 ? 1 : availableSize.Width); reduceText = this.ReduceText(reducedText, ratio); ... 受保护的虚拟字符串 ReduceText(字符串文本,双倍比率){ const double inaccuracy = 0.15;双因子 = 比率 * (1 - 不准确);如果(因子 text.Length) 长度 = text.Length - 1;返回文本。子字符串(0,长度); }
    【解决方案2】:

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

    【讨论】:

    • 确实不错,但我必须“[...] 传入特定数量的字符 [...]” 这意味着它只会起作用对于固定宽度的区域,我将不得不自己估计数量。我正在寻找一种动态解决方案,其中字符数由可用宽度自动估计(就像CharacterEllipsis 在 WPF 中的行为一样)
    • 谢谢,这对我的问题有所帮助。
    【解决方案3】:

    这是我解决缺少 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 :(

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

    【讨论】:

    • 感谢您的回答,希望您注意到这个问题是从 2011 年春季开始的,该项目已经成为历史,但无论如何感谢,它可能对某人有所帮助
    【解决方案4】:
        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;
        }
    

    【讨论】:

      猜你喜欢
      • 2012-08-31
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 2012-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多