Silverlight 替换缺少的文本修剪选项“;“字符省略”;银光中

Silverlight 替换缺少的文本修剪选项“;“字符省略”;银光中,silverlight,silverlight-4.0,texttrimming,Silverlight,Silverlight 4.0,Texttrimming,Silverlight(至少从版本4开始)没有字符省略选项用于文本修剪。它可以用于文本块。这意味着,如果没有足够的空间来显示“那太不可思议了”,我可以删去“那是…”而不是我们更想要的“那是增加的…” 我想,我们应该尝试实现我们的自定义文本修剪功能。基本上,这并不难。一种相当愚蠢的方法是测量字符串的像素,与可用宽度进行比较,然后在文本仍然不适合的情况下,通过剪切最后一个字符并在循环中添加“…”来操纵字符串。下面是一个如何工作的示例: // Not perfect but good enough f

Silverlight(至少从版本4开始)没有
字符省略
选项用于
文本修剪
。它可以用于
文本块
。这意味着,如果没有足够的空间来显示“那太不可思议了”,我可以删去“那是…”而不是我们更想要的“那是增加的…”

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

// 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;
}
//不完美,但对我们来说已经足够好了
私有bool AutoTrim(字符串全文、文本块文本块、双maxWidth)
{
双因素=最大宽度/textBlock.ActualWidth;
如果(系数>1)
返回false;
int newTextLength=(int)Math.Floor((双精度)fullText.Length*因子);
串切试验;
做
{
trimTest=fullText.Substring(0,newTextLength--);
textBlock.Text=trimTest+“…”;//有问题。。。
系数=最大宽度/textBlock.ActualWidth;
}
而(系数<1&&newTextLength>0);
返回true;
}
但是在代码隐藏中(或在
行为中)这样做会导致一些问题:例如,当我们想要更新显示的文本并设置TextBlock的
TextBlock1.text=…
属性时,如果文本绑定到viewModel属性,它实际上可能会更改viewModel。另一个问题发生了,因为我们注意到视图和视图模型可能出于某种原因而运行同步(我们在列表框中注意到)


您对如何更好地解决此问题有何想法?

Dan Wahlin在Silverlight 4中添加TextTrim=“WordEllipsis”之前使用了一个转换器。您可以在这里找到它:

Robby Ingebretsen通过在自定义控件中包装文本块并测量可用大小来实现这一点。它匹配WPF的字符省略号文本修剪模式。Windows Phone 7 Mango中添加了文字省略号模式,但这并没有多大帮助。

以下是我解决缺少字符省略号选项问题的方法。我的解决方案也不是十全十美的,但到目前为止它对我很有效

首先,我添加了以下帮助器方法:

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>
结果:每当MyString属性更改时,就会触发LayoutUpdated事件处理程序并调用AutoTrimTextBlock()方法。如果MyTextBlock太宽,将修剪它的文本属性并追加“…”。这将导致另一个LayoutUpdated事件。该过程将重复,直到MyTextBlock的宽度小于指定的最大值

正如我所说,它不是完美的,也不是特别优雅,但在上面的例子中,它可以正常工作

我不喜欢使用LayoutUpdated事件,但我找不到另一个合适的。TextBlock的TextChanged不存在,很遗憾:(


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

确实很好,但我必须“[…]输入特定数量的字符[…]”这意味着它只适用于固定宽度的区域,我必须自己估算字符数。我正在寻找一种动态解决方案,其中字符数是根据可用宽度自动估算的(就像
CharacterEllipsis
在WPF中的行为一样)谢谢,这帮助我解决了这个问题。很酷!我只发现了一个关于性能的问题-它将原始字符串减少了1个字符,直到达到所需的长度-对于长字符串,它非常慢。查看代码,我想到可以在所需字符串长度和预期字符串长度之间获得一个粗略的比率。以下是我的更改(抱歉-无法对注释进行代码格式设置,并且所有这些对于一条注释来说都太长):…double ratio=换行?textSize.Height/(availableSize.Height==0?1:availableSize.Height):textSize.Width/(availableSize.Width==0?1:availableSize.Width);reducedText=this.reducedText(reducedText,ratio);…受保护的虚拟字符串ReduceText(字符串文本,双精度比){const double inccuracy=0.15;double factor=ratio*(1-不精度);if(factor text.Length)Length=text.Length-1;返回text.Substring(0,Length);}谢谢你的回答,希望你注意到这个问题是从2011年春天开始的,这个项目已经是历史了,但是无论如何,谢谢你,它可能会帮助一些人
    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;
    }
    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;
    }