Why does text of TextPointer vary depending on whether BackgroundProperty is set or not?
-
Monday, August 20, 2012 7:35 PM
After more than a little experimentation, I am kind of seeing double when trying to reliably get the position and text of a FlowDocument TextPointer. Problem is the text I get from the TextPointer varies depending on whether the BackgroundProperty of the text has been set or not.
Is this correct? If so, how do I return the same text at the same offset in the line whether the text has a BackgroundProperty applied to it or not?
In the code sample posted I fill a RichTextBox with 50 lines of text. Then I use GetLineStartPosition and GetPositionAtOffset to set a TextPointer to the start of line 3. Use GetTextInRun to get the text and the return value is an empty string. Then I set a TextRange to the 6 characters of the line and set the BackgroundProperty of that range. The result is only the first 4 chars of the line are highlighted. And when I use GetPositionAtOffset again to get a TextPointer to the first char of the line, GetTextInRun now returns the text of the first 4 chars of the line.
It is all pretty confusing. How do I reliably get the text of a FlowDocument. And how to reliably be able to set the background property of all the characters on the line?
thanks,
<Window x:Class="ColumnSelect.Windows.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> </Grid.RowDefinitions> <RichTextBox x:Name="rbText" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" /> <StackPanel Orientation="Horizontal" Grid.Row="1"> <Button x:Name="but1" Margin="10" Click="but1_Click" >Get Text, then Highlight</Button> <Button x:Name="but2" Margin="10" Click="but2_Click">Get Text, then Highlight, then clear highlighting</Button> </StackPanel> </Grid> </Window> using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ColumnSelect.Windows { /// <summary> /// Interaction logic for Window2.xaml /// </summary> public partial class Window2 : Window { public Window2() { InitializeComponent(); Loaded += Window2_Loaded; } void Window2_Loaded(object sender, RoutedEventArgs e) { FlowDocument flowDoc = new FlowDocument(); var para = new Paragraph(); para.FontSize = 28.0; para.FontFamily = new FontFamily("Lucida console"); for (int cx = 0; cx < 50; ++cx) { Run run = new Run("line:" + cx.ToString()); para.Inlines.Add(run); para.Inlines.Add(new LineBreak()); } flowDoc.Blocks.Add(para); rbText.Document = flowDoc; } private void but1_Click(object sender, RoutedEventArgs e) { var flowDoc = rbText.Document; // position pointer to line 3. var lp1 = flowDoc.ContentStart.GetLineStartPosition(0); lp1 = lp1.GetLineStartPosition(3); TextRange trSave = null; // position pointer at column 0 of line 3. Text of pointer returns blanks. Why? { var tp1 = lp1.GetPositionAtOffset(0); var s1 = tp1.GetTextInRun(LogicalDirection.Forward); Debug.WriteLine("Before setting background property. Text at offset 0 of line 3:" + s1 + " Length:" + s1.Length); } // create textRange from offset 0 to offset 5 of line 3. Then apply a background // property value to the range. Only the first 4 characters are highlighted. // Expecting 6 chars to be highlighted. From offset 0 to offset 5 of the line. { var tp1 = lp1.GetPositionAtOffset(0); var tp2 = lp1.GetPositionAtOffset(5); var tr = new TextRange(tp1, tp2); tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.DarkRed); // save the textRange so the backround property can be cleared later. trSave = tr; } // now that the text is highlighted, get the Text of the TextPointer starting // at offset 0. The text of the text pointer now shows a value. But only the first // 4 chars. In the code just run before setting the background property, the text // was blank. { var tp1 = lp1.GetPositionAtOffset(0); var s1 = tp1.GetTextInRun(LogicalDirection.Forward); Debug.WriteLine("After setting background property. Text at offset 0 of line 3:" + s1); } Debug.WriteLine("---------------------"); } private void but2_Click(object sender, RoutedEventArgs e) { var flowDoc = rbText.Document; // position pointer to line 3. var lp1 = flowDoc.ContentStart.GetLineStartPosition(0); lp1 = lp1.GetLineStartPosition(3); TextRange trSave = null; // position pointer at column 0 of line 3. Text of pointer returns blanks. Why? { var tp1 = lp1.GetPositionAtOffset(0); var s1 = tp1.GetTextInRun(LogicalDirection.Forward); Debug.WriteLine("Before setting background property. Text at offset 0 of line 3:" + s1); } // create textRange from offset 0 to offset 5 of line 3. Then apply a background // property value to the range. Only the first 4 characters are highlighted. // Expecting 6 chars to be highlighted. From offset 0 to offset 5 of the line. { var tp1 = lp1.GetPositionAtOffset(0); var tp2 = lp1.GetPositionAtOffset(5); var tr = new TextRange(tp1, tp2); tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.DarkRed); // save the textRange so the backround property can be cleared later. trSave = tr; } // now that the text is highlighted, get the Text of the TextPointer starting // at offset 0. The text of the text pointer now shows a value. But only the first // 4 chars. In the code just run before setting the background property, the text // was blank. { var tp1 = lp1.GetPositionAtOffset(0); var s1 = tp1.GetTextInRun(LogicalDirection.Forward); Debug.WriteLine("After setting background property. Text at offset 0 of line 3:" + s1); } // clear the background property. Get the text at offset 0 of the line again. The // text now shows as the full 6 characters of the line. { trSave.ApplyPropertyValue(TextElement.BackgroundProperty, null); var tp1 = lp1.GetPositionAtOffset(0); var s1 = tp1.GetTextInRun(LogicalDirection.Forward); Debug.WriteLine("After background is cleared. Text at offset 0 of line 3:" + s1); } Debug.WriteLine("---------------------"); } } }
All Replies
-
Tuesday, August 21, 2012 7:47 AMModerator
Hi Steve Richter,
The cause of your issue it "GetLineStartPosition" give the position which is not surrounded by any text, it is not a insert position, so you could not get any text by
"GetTextInRun(LogicalDirection.Forward);"
and
" var tp1 = lp1.GetPositionAtOffset(0);
var tp2 = lp1.GetPositionAtOffset(5);"will be first "4" insert text.
You could use "GetInsertionPosition" method to fix your issue, refer to below code snippet:
lp1 = lp1.GetLineStartPosition(3).GetInsertionPosition(LogicalDirection.Backward);
Best regards,
Sheldon _Xiao[MSFT]
MSDN Community Support | Feedback to us
Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
- Marked As Answer by Steve Richter Tuesday, August 21, 2012 8:45 PM

