包装在wpf文本块控件中时保留缩进

时间:2014-08-27 13:54:58

标签: wpf vb.net xaml textblock textwrapping

我设置了一个WPF文本块,其属性为TextWrapping =“Wrap”。

当我在开头传入一个带有制表符(我的情况下是vbTab)的长字符串时,我希望包装符合这一点并保持字符串的包裹部分缩进。 例如,而不是:

  

[vbTab] thisisreallylong

     

andwrapped

我想要

  

[vbTab] thisisreallylong

     

[vbTab] andwrapped

,理想情况下也适用于多个标签等。

[编辑 - 其他详细信息]

因为文本块的大小可变,并且包含多行文本以及各种缩进量,所以我不能只有一个边距或手动拆分字符串并添加标签。

基本上我想要的是它处理像段落一样的文本行,在它们换行时保持缩进。

1 个答案:

答案 0 :(得分:4)

根据您的想法,我能够提出这个解决方案

我会将每行开头的所有标签转换为每个0.5英寸的边距,并在段落中添加相同的文字并将计算的边距应用于相同的

TextBlock是不可行的,因为它对于运行粗体,内联ui容器等基本文本内联很有用。在TextBlock中添加段落更复杂,所以我根据FlowDocument制作了解决方案。

<强>结果

result

以下示例使用FlowDocumentScrollViewerRichTextBoxFlowDocumentReader或普通FlowDocument

演示同样的内容

我已经使用附加属性创建了解决方案,因此您可以将其附加到任何提到的内容,甚至可以为文档添加自己的主机。您只需将IndentationProvider.Text设置为所需的主机即可。

<强> XAML

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:l="clr-namespace:PreservingIndentationDemo"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.Resources>
        <sys:String x:Key="longString"
                    xml:space="preserve">&#x09;this is really long and wrapped

&#x09;&#x09;another line this is also really long and wrapped

&#x09;one more line this is also really long and wrapped

another line this is also really long and wrapped

&#x09;&#x09;another line this is also really long and wrapped
        </sys:String>
    </Window.Resources>
    <Grid>
        <FlowDocumentScrollViewer l:IndentationProvider.Text="{StaticResource longString}" />
        <!--<RichTextBox l:TextToParaHelper.Text="{StaticResource longString}" IsReadOnly="True"/>-->
        <!--<FlowDocumentReader l:TextToParaHelper.Text="{StaticResource longString}" />-->
        <!--<FlowDocument l:TextToParaHelper.Text="{StaticResource longString}" />-->
    </Grid>
</Window>

&#x09;指的是tab char

<强> IndentationProvider

Class IndentationProvider

    Public Shared Function GetText(obj As DependencyObject) As String
        Return DirectCast(obj.GetValue(TextProperty), String)
    End Function

    Public Shared Sub SetText(obj As DependencyObject, value As String)
        obj.SetValue(TextProperty, value)
    End Sub

    ' Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
    Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.RegisterAttached("Text", GetType(String), GetType(IndentationProvider), New PropertyMetadata(Nothing, AddressOf OnTextChanged))

    Private Shared Sub OnTextChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
        Dim blocks As BlockCollection = Nothing

        Dim rtb As RichTextBox = TryCast(d, RichTextBox)
        If rtb IsNot Nothing Then
            rtb.Document.Blocks.Clear()
            blocks = rtb.Document.Blocks
        End If

        If blocks Is Nothing Then
            Dim fd As FlowDocument = TryCast(d, FlowDocument)
            If fd IsNot Nothing Then
                fd.Blocks.Clear()
                blocks = fd.Blocks
            End If
        End If

        If blocks Is Nothing Then
            Dim fdr As FlowDocumentReader = TryCast(d, FlowDocumentReader)
            If fdr IsNot Nothing Then
                fdr.Document = New FlowDocument()
                blocks = fdr.Document.Blocks
            End If
        End If

        If blocks Is Nothing Then
            Dim fdr As FlowDocumentScrollViewer = TryCast(d, FlowDocumentScrollViewer)
            If fdr IsNot Nothing Then
                fdr.Document = New FlowDocument()
                blocks = fdr.Document.Blocks
            End If
        End If

        Dim newValue As String = TryCast(e.NewValue, String)
        If Not String.IsNullOrWhiteSpace(newValue) Then
            For Each line As String In newValue.Split(ControlChars.Lf)
                Dim leftMargin As Double = 0
                Dim newLine As String = line
                While newLine.Length > 0 AndAlso newLine(0) = ControlChars.Tab
                    leftMargin += 0.5
                    newLine = newLine.Remove(0, 1)
                End While
                Dim marginInch As String = leftMargin & "in"
                Dim marginDip As Double = CDbl(New LengthConverter().ConvertFromString(marginInch))

                Dim para As New Paragraph(New Run(newLine)) With {.Margin = New Thickness(marginDip, 0, 0, 0)}
                blocks.Add(para)
            Next
        End If
    End Sub
End Class

<强>演示

尝试demo project