简体   繁体   English

在wpf文本块中的多个跨度/区域上动态更改文本修饰

[英]dynamically change text decorations on multiple spans/regions in a wpf textblock

I am trying to design an app that strikes out certain characters on a string if another 1 or 2 strings are contained within that string. 我正在尝试设计一个应用程序,如果该字符串中包含其他1或2个字符串,则会删除该字符串上的某些字符。

So far I can seem to get the leading sub string to do its thing fairly reliably, but the second sub-string always seems to produce unpredictable results, can anyone help? 到目前为止,我似乎可以使前导子字符串相当可靠地完成其工作,但是第二个子字符串似乎总是产生不可预测的结果,有人可以帮助吗? (c# or vb is fine) (C#或VB可以)

A screen snip example of it working for the main (1st) filter, but not the sub (2nd): 它的屏幕截图示例适用于主过滤器(第一个),但不适用于子过滤器(第二个): 在此处输入图片说明

Heres the code: 这是代码:

Public Function FormatFilteredName(mainFilter As String, subFilter As String) As TextBlock
    Dim tbNew As New TextBlock(New Run(FullFileName))
    tbNew.Text = FullFileName
    tbNew.FontSize = FONT_SIZE
    If Not String.IsNullOrEmpty(FullFileName) Then
        If Not String.IsNullOrEmpty(mainFilter) Then
            GetFilterSpan(mainFilter, tbNew)
        End If
        If Not String.IsNullOrEmpty(subFilter) Then
            GetFilterSpan(subFilter, tbNew)
        End If
    End If
    Return tbNew

Private Function GetFilterSpan(filter As String, ByVal tbNew As TextBlock) As Span
    Dim offset As Integer = tbNew.Text.ToLower().IndexOf(filter.ToLower()) + 1
    Try
        If offset > -1 Then
            Dim tpStart As TextPointer
            tpStart = tbNew.ContentStart.GetPositionAtOffset(offset)
            Dim tpEnd As TextPointer
            tpEnd = tbNew.ContentStart.GetPositionAtOffset(offset + filter.Length)
            If Not tpStart Is Nothing And Not tpEnd Is Nothing Then
                Dim result As New Span(tpStart, tpEnd)
                result = ApplySpanStrikeOutStyle(result)
                Return result
            End If
        End If
    Catch ex As Exception
        Return Nothing
    End Try

If you run your code with a watch set on tbNew.ContentEnd.Offset, you'll see the value change as the strikethroughs are applied. 如果使用在tbNew.ContentEnd.Offset上设置的监视来运行代码,则将在应用删除线后看到值更改。 That illustrates why using 这说明了为什么使用

Dim offset As Integer = tbNew.Text.ToLower().IndexOf(filter.ToLower()) + 1

is not accurate - you're getting the IndexOf from the plain text, and then applying that offset to content which has text decorations applied. 是不准确的-您是从纯文本获取IndexOf,然后将该偏移量应用于已应用文本修饰的内容。

From the answer here , this should get you on your way. 根据这里的答案,这应该可以助您一臂之力。

  Public Function FormatFilteredName(mainFilter As String, subFilter As String) As TextBlock
        ' Dim tbNew As New TextBlock(New Run("111xxJoe Blogs09"))
        ' tbNew.Text = "111xxJoe Blogs09"
        ' tbNew.FontSize = 10
        If Not String.IsNullOrEmpty(tbNew.Text) Then
            If Not String.IsNullOrEmpty(mainFilter) Then
                Dim mainFilterRange As TextRange = FindWordFromPosition(tbNew.ContentStart, mainFilter)
                If mainFilterRange IsNot Nothing Then
                    ApplyStrikeOutStyle(mainFilterRange)
                End If
            End If
            If Not String.IsNullOrEmpty(subFilter) Then
                Dim subFilterRange As TextRange = FindWordFromPosition(tbNew.ContentStart, subFilter)
                If subFilterRange IsNot Nothing Then
                    ApplyStrikeOutStyle(subFilterRange)
                End If
            End If
        End If
        Return tbNew
    End Function



    Private Function ApplyStrikeOutStyle(result As TextRange) As TextRange
        result.ApplyPropertyValue(Inline.TextDecorationsProperty,
                             TextDecorations.Strikethrough)
        Return result
    End Function


    Private Function FindWordFromPosition(position As TextPointer, word As String) As TextRange
        While position IsNot Nothing
            If position.GetPointerContext(LogicalDirection.Forward) = TextPointerContext.Text Then
                Dim textRun As String = position.GetTextInRun(LogicalDirection.Forward)

                ' Find the starting index of any substring that matches "word".
                Dim indexInRun As Integer = textRun.IndexOf(word)
                If indexInRun >= 0 Then
                    Dim start As TextPointer = position.GetPositionAtOffset(indexInRun)
                    Dim [end] As TextPointer = start.GetPositionAtOffset(word.Length)
                    Return New TextRange(start, [end])
                End If
            End If

            position = position.GetNextContextPosition(LogicalDirection.Forward)
        End While

        ' position will be null if "word" is not found.
        Return Nothing
    End Function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM