2011-05-25 33 views
2

Silverlight(至少在版本4時)沒有CharacterEllipsis選項用於TextTrimming,其中WPF has。它可以在TextBlock上使用。這意味着,如果沒有足夠的空間來顯示「這是不可思議的」,我可以修剪爲「這就是...」,但不是「我們想要的那個......」。在Silverlight中丟失TextTrimming選項「CharacterEllipsis」的替換

雖然我們會嘗試實現我們的自定義文本修剪功能。基本上,那不是那麼難。一個非常愚蠢的方法是測量字符串的像素,與可用寬度進行比較,並通過剪切最後一個字符並在循環中添加「...」來處理字符串,而文本仍然不適合。下面是一個例子,如何這可能是工作:

// 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 = ...物業如果Text綁定到ViewModel屬性,它實際上可能會改變我們的viewModel。由於我們注意到view和viewModel可能由於某種原因(我們注意到在ListBox中)發生了同步運行,所以出現了另一個問題。

對於如何以良好的方式解決這個問題你有更好的想法嗎?

回答

3

丹Wahlin使用轉換器的TextTrimming =「WordEllipsis」加入的Silverlight 4之前,您可以在這裏找到:http://weblogs.asp.net/dwahlin/archive/2010/05/05/text-trimming-in-silverlight-4.aspx

+0

這的確不錯,但我將不得不「* [...]傳中特定數量的字符[...] *「這意味着它只適用於固定寬度區域,我將不得不自己估計數字,我正在尋找一種動態解決方案,通過可用寬度自動估計字符數量(就像'CharacterEllipsis'行爲一樣在WPF中) – thmshd 2011-06-01 19:38:40

+0

Thanks,this help me with our issue。 – cunningdave 2012-06-11 18:32:47

5

羅比Ingebretsen的DynamicTextBox在自定義控件包裹的TextBlock和測量可用大小做到這一點。它匹配WPF的CharacterEllipsis文本修剪模式。 WordEllipsis模式確實已被添加到Windows Phone 7 Mango中,但在這裏沒有多大幫助。

+0

Cool! 我發現只有一個關於性能的問題 - 它將原始字符串減少1個字符,直到達到所需的長度 - 對於長字符串它非常緩慢。 查看代碼,我發現我們可以在期望和期望的字符串長度之間有一個大致的比例。下面是我的更改(對不起 - 評論無法進行代碼格式化,所有這些對於一個評論來說都太長): – sarh 2013-09-13 14:45:39

+0

... double ratio = wrapping ?textSize.Height /(availableSize.Height == 0?1:ava iSizeSize.Height) :textSize.Width /(availableSize.Width == 0? 1:availableSize.Width); reducedText = this.ReduceText(reducedText,ratio); ... 受保護的虛擬字符串ReduceText(字符串文本,雙倍比率) const double double miscuracy = 0.15; double factor = ratio *(1 - 不準確); if(factor <= 0) factor = 1; int length =(int)(text.Length/factor); if(length <0 || length> text.Length) length = text.Length - 1; return text.Substring(0,length); } – sarh 2013-09-13 14:47:31

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事件處理程序就會被觸發,Au toTrimTextBlock()方法被調用。如果MyTextBlock太寬,它的Text屬性將被修剪,並且附加'...'。這會導致另一個LayoutUpdated事件。該過程重複,直到MyTextBlock的寬度小於指定的最大值。

正如我所說,它並不完美,不是特別優雅,但它在上述例子中起作用。

我不喜歡使用LayoutUpdated事件的想法,但我找不到其他合適的事件。框TextChanged不存在TextBlock的,不幸的是:(

請讓我知道如果有什麼我可以提高。

+0

感謝您的回答,希望您注意到這個問題是從2011年春季開始的,該項目已經成爲歷史,但無論如何感謝,它可能會幫助某人 – thmshd 2014-03-19 12:02:07

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