I have two FlowDocuments side by side in two different stack panels. I need a way to search both the documents at the same time for a particular text. As in if I type "car" in the text box both flow document reader should and search for and scroll to the next instance of "car" if there is one. Is there any way to achieve this? The FlowDocument is inside a FlowDocumentReader.
Asked
Active
Viewed 173 times
2 Answers
3
Here I have a basic WPF XAML layout, with 2 FlowDocumentReaders as you specified. I have a search TextBox and am going to run the code behind whenever the search text changes:
<Window x:Class="WpfFlowTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfFlowTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<!-- Search Box -->
<TextBox Name="SearchTextBox" DockPanel.Dock="Top" TextChanged="TextBox_TextChanged"/>
<!-- 2 Flow Readers -->
<UniformGrid Columns="2">
<FlowDocumentReader Name="FlowReader1">
<FlowDocument>
<Paragraph>
Here is some text in panel number 1
</Paragraph>
</FlowDocument>
</FlowDocumentReader>
<FlowDocumentReader Name="FlowReader2">
<FlowDocument>
<Paragraph>
Here is some more text in panel number 2
</Paragraph>
</FlowDocument>
</FlowDocumentReader>
</UniformGrid>
</DockPanel>
</Window>
In the MainWindow.xaml.cs file I have this code which will highlight the flow document where the text matches what you typed in:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = SearchTextBox.Text;
DoSearch(FlowReader1, searchText);
DoSearch(FlowReader2, searchText);
}
private void DoSearch(FlowDocumentReader reader, string search)
{
var doc = reader.Document;
var text = doc.ContentStart;
var docRange = new TextRange(doc.ContentStart, doc.ContentEnd);
docRange.ClearAllProperties();
while (true)
{
var next = text.GetNextContextPosition(LogicalDirection.Forward);
if (next == null)
{
break;
}
var txt = new TextRange(text, next);
int indx = txt.Text.IndexOf(search);
if (indx > 0)
{
var sta = text.GetPositionAtOffset(indx);
var end = text.GetPositionAtOffset(indx + search.Length);
var textR = new TextRange(sta, end);
// Make it yellow
textR.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
}
text = next;
}
}

Jon
- 3,230
- 1
- 16
- 28
-
Is there a way to scroll the document to the highlighted text? – jailorboy Jul 20 '16 at 14:10
-
To my knowledge, there isn't a built-in way to scroll the document to the highlighted text, but you can calculate it yourself if you know the `LineHeight`, `PagePadding`, and any other padding or margins (like spacing between paragraphs) in your document. – Meloviz Jul 20 '16 at 14:20
-
I was hoping for a way to use the BringIntoView() method to scroll the document. – jailorboy Jul 20 '16 at 14:38
-
I've posted my slight modification for people who want to scroll. – jailorboy Jul 20 '16 at 15:27
-
My FlowDocument contains a table and for some reason, whenever I search for anything in the last row, sta and/or end always come null. – jailorboy Jul 20 '16 at 18:08
0
I've posted my slight modification for people who want to scroll.
private void TextBox_TextChanged(object sender, EventArgs e)
{
var searchText = SearchTextBox.Text;
if (searchText != null || searchText != "")
{
var FlowReader1 = (FlowDocumentReader)diffResults.Children[0];
var FlowReader2 = (FlowDocumentReader)oldResults.Children[0];
DoSearch(FlowReader1, searchText);
DoSearch(FlowReader2, searchText);
}
}
private void DoSearch(FlowDocumentReader reader, string search)
{
bool toScroll = true;
var doc = reader.Document;
var text = doc.ContentStart;
var docRange = new TextRange(doc.ContentStart, doc.ContentEnd);
docRange.ClearAllProperties();
while (true)
{
var next = text.GetNextContextPosition(LogicalDirection.Forward);
if (next == null)
{
break;
}
var txt = new TextRange(text, next);
int indx = txt.Text.IndexOf(search);
if (indx >= 0)
{
var sta = text.GetPositionAtOffset(indx);
var end = text.GetPositionAtOffset(indx + search.Length);
if (end == null)
{
end = text.GetPositionAtOffset(indx + 1);
}
var textR = new TextRange(sta, end);
if (toScroll && text.Paragraph != null)
{
text.Paragraph.BringIntoView();
toScroll = false;
}
// Make it yellow
textR.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
}
text = next;
}

jailorboy
- 33
- 5
-
While `BringIntoView()` does actually bring it into the `Viewport`, it doesn't necessarily bring it to any preset position in the `Viewport`, which I guess is what you were looking for, sorry. I just assumed you wanted it at the top of the `Viewport`, so that's my bad. But if you want to bring the text to the very top of the it, unless there's something out there I don't know, you would actually have to calculate it. That's what I had to do. – Meloviz Jul 20 '16 at 15:53
-