在 wpf 文本块控件中换行时保留缩进

问题描述 投票:0回答:1

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

当我在开头传递一个带有制表符(在我的例子中为 vbTab)的长字符串时,我希望换行能够遵循这一点并保持字符串的换行部分缩进。 例如,代替:

[vbTab]这真的很长

并包裹

我想要

[vbTab]这真的很长

[vbTab]并包裹

并且非常适合多个选项卡等。

[编辑 - 其他详细信息]

因为文本块的大小可变,并且包含具有不同缩进量的多行文本,所以我不能只留边距或手动拆分字符串并添加制表符。

本质上我想要的是将文本行视为段落,在换行时保持缩进。

wpf vb.net xaml textblock word-wrap
1个回答
4
投票

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

我会将每行开头的所有制表符转换为 0.5 英寸边距,并在段落中添加相同的文本,并将计算出的边距应用于相同的内容

TextBlock 不可行,因为它对于基本文本内联(如运行粗体、内联 ui 容器等)很有用。在 TextBlock 中添加段落更加复杂,因此我基于 FlowDocument 制定了解决方案。

结果

result

下面的示例使用

FlowDocumentScrollViewer
RichTextBox
FlowDocumentReader
或普通
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;
指制表符

缩进提供者

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

演示

尝试演示项目

© www.soinside.com 2019 - 2024. All rights reserved.