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.
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)
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. 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.
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