XAML 在wpf textblock控件中换行时保留缩进

v64noz0r  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(177)

我有一个WPF文本块设置为属性TextWrapping=“Wrap”。
当我传入一个开头带有制表符的长字符串(在我的例子中是vbTab)时,我希望 Package 能够尊重这一点,并保持字符串 Package 部分的缩进。例如,而不是:
[vbTab]thisisreallylong
和 Package
我想
[vbTab]thisisreallylong
[vbTab]和 Package
并且理想地用于多个标签等。也

[edit - additional details]

因为文本块的大小是可变的,并且包含多行具有不同缩进量的文本,所以我不能只留一个边距或手动拆分字符串并添加制表符。
从本质上讲,我想要的是它像对待段落一样对待文本行,在换行时保持缩进。

e1xvtsh3

e1xvtsh31#

根据你的想法,我能想出这个解决办法
我将转换所有的制表符在每一行的开始,以.5英寸的保证金,并将添加相同的文字在一个段落,并适用于计算的保证金相同
TextBlock不适用于基本文本内联,如run bold,内联ui容器等。在TextBlock中添加段落更加复杂,因此我基于FlowDocument提出了解决方案。

结果

下面的示例使用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;指制表符

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

尝试demo project

相关问题