2015-06-10 23 views
2

我使用一個列表框來顯示撤銷重做列表數據模板:文本換行與WPF文本塊縮進

<ListBox x:Name="actionList" 
      Height="150" 
      HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch" 
      MouseMove="ListBoxMouseMove" 
      ScrollViewer.VerticalScrollBarVisibility="Visible" 
      SelectionMode="Extended" 
      Style="{StaticResource CustomListBoxStyle}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
     <TextBlock Width="235" 
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        FontSize="11" 
        Text="{Binding DisplayText}" 
        TextWrapping="Wrap" /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
    </ListBox> 

它工作正常,但長期撤銷重做串發生纏繞,但它是與該行的第一個字符對齊。我們希望它縮進一點以清楚地標識這兩個列表項。舉例說明如下:

Word wrap desired functionality

我們如何才能達到相同的。

+0

據我所知,這是不可能的*很容易*。你需要計算出新字符串的哪一部分,並縮進RichTextBox中的那部分字符串。那會導致無數的頭痛。也許設計變更是這裏需要的?也許你可以爲文本提供一些**填充,以便列表中的項目間隔更遠。 –

回答

1

我必須使用轉換器找到一個解決辦法:

<ListBox x:Name="actionList" 
       Height="150" 
       HorizontalAlignment="Stretch" 
       VerticalAlignment="Stretch" 
       MouseMove="ListBoxMouseMove" 
       ScrollViewer.VerticalScrollBarVisibility="Visible" 
       SelectionMode="Extended" 
       Style="{StaticResource CustomListBoxStyle}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
      <TextBlock x:Name="textBlock" 
         Width="235" 
         HorizontalAlignment="Stretch" 
         VerticalAlignment="Stretch" 
         FontSize="11" 
         Text="{Binding DisplayText, 
             Converter={StaticResource indentWrapConverter}, 
             ConverterParameter=235}" 
         TextWrapping="Wrap"/> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
     </ListBox> 

器和轉換器類:

namespace XXXX.Converters 
{ 
    using System; 
    using System.Text; 
    using System.Globalization; 
    using System.Windows.Data; 

    /// <summary> 
    /// Wrap converter for text block to indent wrapped line a bit to identify 
    /// it correctly 
    /// </summary> 
    public class IndentWrapConverter : IValueConverter 
    { 
    #region Implementation of IValueConverter 

    /// <summary> 
    /// Wrap the passed-in text as per passed-in textblock width, after warpping it 
    /// adds whitepsaces to indent the next lines 
    /// </summary> 
    /// <returns> 
    /// A converted value. If the method returns null, the valid null value is used. 
    /// </returns> 
    /// <param name="value">The value produced by the binding source.</param><param name="targetType">The type of the binding target property.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param> 
    public object Convert(object value, 
          Type targetType, 
          object parameter, 
          CultureInfo culture) 
    { 
     // get the string of textblock 
     var stringData = value as string; 

     // if string cant be parsed retrurn null 
     if (stringData == null) 
     { 
     return null; 
     } 

     // get textblock width 
     var width = 235.0; 
     double.TryParse(parameter.ToString(), 
         out width); 

     // get actual length by using text block width divide by font size 
     int length = (int)Math.Round((2 * width/11)); 

     // if text length is less than calulated length then return string as it is 
     // else wrap the text 
     return stringData.Length > length 
      ? WordWrap(stringData, 
         length) 
      : stringData; 
    } 



    /// <summary> 
    /// Word wraps the given text to fit within the specified width. 
    /// </summary> 
    /// <param name="text">Text to be word wrapped</param> 
    /// <param name="width">Width, in characters, to which the text 
    /// should be word wrapped</param> 
    /// <returns>The modified text</returns> 
    private static string WordWrap(string text, 
            int width) 
    { 
     int pos, next; 
     StringBuilder sb = new StringBuilder(); 

     // Lucidity check 
     if (width < 1) 
     return text; 

     // Parse each line of text 
     for (pos = 0; pos < text.Length; pos = next) 
     { 
     // Find end of line 
     int eol = text.IndexOf(Environment.NewLine, 
           pos, 
           StringComparison.Ordinal); 
     if (eol == -1) 
      next = eol = text.Length; 
     else 
      next = eol + Environment.NewLine.Length; 

     // Copy this line of text, breaking into smaller lines as needed 
     if (eol > pos) 
     { 
      do 
      { 
      int len = eol - pos; 
      if (len > width) 
       len = BreakLine(text, pos, width); 
      sb.Append(text, pos, len); 
      if (pos < width) 
      { 
       sb.Append(Environment.NewLine); 
       sb.Append(" "); 
      } 

      // Trim whitespace following break 
      pos += len; 
      while (pos < eol && Char.IsWhiteSpace(text[pos])) 
       pos++; 
      } while (eol > pos); 
     } 
     } 
     return sb.ToString(); 
    } 

    /// <summary> 
    /// Locates position to break the given line so as to avoid 
    /// breaking words. 
    /// </summary> 
    /// <param name="text">String that contains line of text</param> 
    /// <param name="pos">Index where line of text starts</param> 
    /// <param name="max">Maximum line length</param> 
    /// <returns>The modified line length</returns> 
    private static int BreakLine(string text, int pos, int max) 
    { 
     // Find last whitespace in line 
     int i = max; 
     while (i >= 0 && !Char.IsWhiteSpace(text[pos + i])) 
     i--; 

     // If no whitespace found, break at maximum length 
     if (i < 0) 
     return max; 

     // Find start of whitespace 
     while (i >= 0 && Char.IsWhiteSpace(text[pos + i])) 
     i--; 

     // Return length of text before whitespace 
     return i + 1; 
    } 


    /// <summary> 
    /// Converts a value. 
    /// </summary> 
    /// <returns> 
    /// A converted value. If the method returns null, the valid null value is used. 
    /// </returns> 
    /// <param name="value">The value that is produced by the binding target.</param><param name="targetType">The type to convert to.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param> 
    public object ConvertBack(object value, 
           Type targetType, 
           object parameter, 
           CultureInfo culture) 
    { 
     return null; 
    } 

    #endregion 
    } 
} 

與列表框造型和選擇所需的工作。

1

他們「更簡單」的方式可能會涉及使用段落對象來表示文本。

段本身支持具有屬性壓痕等TextIndent(對照首行縮進,並且可以將其設置爲負值)或保證金(設置爲全段的餘量,但尊重首行縮進) 。

<ListBox.ItemTemplate> 
    <DataTemplate> 
     // IsHitTestVisible is set to false to avoid FlowDocument's built-in text selection 
     //  from disrupting the regular ListBox mouse selection behavior 
     <Grid IsHitTestVisible="False"> 
      <FlowDocumentScrollViewer ScrollViewer.VerticalScrollBarVisibility="Disabled" 
             ScrollViewer.HorizontalScrollBarVisibility="Disabled"> 
       <FlowDocument FontSize="12" 
           FontFamily="Calibri" 
           Foreground="Black" 
           PagePadding="0"> 
        <Paragraph TextIndent="-10" 
           Margin="10,0,0,0"> 
         <Run Text="{Binding ., Mode=OneWay}" /> 
        </Paragraph> 
       </FlowDocument> 
      </FlowDocumentScrollViewer> 
     </Grid> 
    </DataTemplate> 
</ListBox.ItemTemplate> 
+0

如何將段落作爲列表框項? – Mohit

+0

編輯我有一個代碼示例的答案,並取消了BindableRun的事情,因爲運行的確是綁定,因爲4.0(示例使用一個ListView,而不是一個列表框,但你可以看到這個想法:P) – almulo

+0

它沒有工作,但失去了列表框的功能和造型。我無法顯示選定的項目和樣式相同是太多的任務。 – Mohit