I am replacing a TextBox with a RichTextBox in WPF (.NET 6) and had a hard time porting the search code. I've tried TextRange and TextPointer using the GetOffset()
methods, but nothing has worked. However, the code below works. It looks like a workaround to me and maybe one of you finds it helpful or knows a better way of doing it.
var textRange = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
var text = textRange.Text;
int startIndex = 0;
// Set the start index to the offset
if (StartPosition != null)
{
startIndex = textRange.Start.GetOffsetToPosition(StartPosition);
}
SearchResultValue searchResult;
var result = text.IndexOf(SearchPattern, startIndex, comparison);
// Any result value of 0 or greater indicates a hit
if (result >= 0)
{
// Hit
var selectionStart = textRange.Start.GetPositionAtOffset(result);
// Iterate over the index positions until the end of the search pattern. Is there a better way of doing it?
var currentSelection = textRange.Start.GetPositionAtOffset(result);
for (int run = 0; run < SearchPattern.Length; run )
{
currentSelection = currentSelection.GetNextInsertionPosition(LogicalDirection.Forward);
}
var selectedRange = new TextRange(selectionStart, currentSelection);
searchResult = new SearchResultValue(true, selectedRange);
}
else
{
// No hit
searchResult = new SearchResultValue(false, null);
}
return searchResult;
/// <summary>
/// Specifies the result of the search operation
/// </summary>
/// <param name="Successful">true if any content has been found</param>
/// <param name="start">the start index</param>
/// <param name="length">the length</param>
internal record struct SearchResultValue(bool Successful, TextRange ? Selection);
Is there a better way of doing it? I've invested time in browsing the MSDN and other resources and this is the best I could find. But I am new to this control as well.
Thansk!
CodePudding user response:
I could finally solve it. The only solution seems to be parsing each paragraph and search on the text in each of them. To give you an idea of what I mean:
internalSearchPosition is a private TextPointer instance and stores the latest hit. SearchResultValue is just a return value for my view model logic. The entire code is too long for posting, but this is the core of the search functionality.
while (currentBlock != null)
{
var paragraph = currentBlock as Paragraph;
if (paragraph != null)
{
//
// Get the range of the paragraph content and search for the pattern
//
var paragraphRange = new TextRange(internalSearchPosition, paragraph.ContentEnd);
var paragraphText = paragraphRange.Text;
int result = paragraphText.IndexOf(searchPattern, comparison);
if (result >= 0)
{
//
// Hit. Build the search result and leave the for each loop
//
var startSelection = paragraph.ContentStart.GetPositionAtOffset(result);
var endSelection = startSelection.GetPositionAtOffset(searchPattern.Length 1);
searchResult = new SearchResultValue(true, new TextRange(startSelection,endSelection));
// Save the current position
internalSearchPosition = endSelection;
break;
}
}
// Go to the next block or leave the loop when NextBlock is null (end of paragraphs). Also reset the internal search position if required.
currentBlock = currentBlock.NextBlock;
if (currentBlock != null)
{
internalSearchPosition = currentBlock.ContentStart;
}
}