WPF RichTextBox scroll to TextPointer - c#

The WPF RichtTextBox has a method to scroll:
RichTextBox.ScrollToVerticalOffset(double)
I want to scroll in such a way, that a certain range or at least the start of it comes into view. How can I convert a TextPointer to double in a meaningful way?

Have a look at the FrameworkElement.BringIntoView Method. I'm using something like this:
public void Foo(FlowDocumentScrollViewer viewer) {
TextPointer t = viewer.Selection.Start;
FrameworkContentElement e = t.Parent as FrameworkContentElement;
if (e != null)
e.BringIntoView();
}

I'm somewhat late, but here is a more complete answer. The current scroll offsets need to be combined with the character position. Here is an example that scrolls RichTextBox text pointer to the center of the view:
var characterRect = textPointer.GetCharacterRect(LogicalDirection.Forward);
RichTextBox.ScrollToHorizontalOffset(RichTextBox.HorizontalOffset + characterRect.Left - RichTextBox.ActualWidth / 2d);
RichTextBox.ScrollToVerticalOffset(RichTextBox.VerticalOffset + characterRect.Top - RichTextBox.ActualHeight / 2d);
You don't need to check for negative numbers, as the scrolling accounts for this.

Use GetCharacterRect to get position of TextPointer in RichTextBox:
Rect r = textPointer.GetCharacterRect(LogicalDirection.Backward);
rtb.ScrollToVerticalOffset(r.Y);

So if you're wondering why BringIntoView() isn't working or it scrolls to the top of your textbox, it's likely because you are attempting to "bring into view" the Inline that comprises your entire scrollable text content - it "brings to view" this inline, which starts at (you guessed it) the "start" TextPosition at the top.
Solution is to use ScrollToVerticalOffset() per Miroslav's answer.

Related

Get the position (x,y) of the first character of the text within a text box in WPF

How to convert the first character index within the textbox to the x,y coordinates in WPF ie basically I need the point loaction of the first character of the text within a textbox in WPF.I am capturing the x,y coordinates of the textbox wrt image displayed on the window screen in wpf
UIElement container = (MainImage) as UIElement; System.Windows.Point relativeLocation = textboxinsert.TranslatePoint(new System.Windows.Point(0, 0), container);
But unaware to do it for text within a textbox in wpf.Any pointers would be really helpful?
If you only need to find the position of the first appearance, you will be fine with TextBox.Text.IndexOf('x');.
If you need to row too, you will need to make a difference between the lines that are broken because of the size of the textbox and the ones that are there because the user has pressed Enter.
You can do it by using a MemoryStream and a StreamReader.

Check how many lines TextView will have before it's displayed

In my app, I need text in myTextView to display single line without the three dots at the end. I need to show a little differently formatted text when it's too long, so something like setting maxHeight won't help since it just crops it.
My approach was to check how many lines the TextView has, and make the text in shorter if it has more than 1. This is exactly the approach I want, but since the View has to be drawn first to check LineCount, two-line layout flashes briefly before cutting the text to one-line:
myTextView.Post(() =>
{
if (myTextView.LineCount > 1)
{
// make text shorter here to fit 1 line
}
});
So my question is, is there any way to check how many lines the View will have before it is displayed to the user? I could force it based on character count in a string, but that seems wrong.
Firstly, set TextView Visibility to Invisible so that it takes up its space and then populate it.
There is a method that you can use to get the line count.
TextView txt = (TextView)findViewById(R.id.txt);
txt.getLineCount();
This returns an "int".
Use that int in your textChangedListener to play with the visibility of TextView.
This way you will know that how many line break does the TextView has.
Cheers.
So I came to a solution that works for me. It requires getting the screen width, calculating the width of the TextView and checking text length, everything in dp. So:
// get the screen width
var metrics = Resources.DisplayMetrics;
var widthInDp = (int)((metrics.WidthPixels) / metrics.Density);
// this line is very specific, it calculates the real usable space
// in my case, there was padding of 5dp nine times, so subtract it
var space = widthInDp - 9 * 5;
// and in this usable space, I had 7 identical TextViews, so a limit for one is:
var limit = space / days.Length;
// now calculating the text length in dp
Paint paint = new Paint();
paint.TextSize = myTextView.TextSize;
var textLength = (int)Math.Ceiling(paint.MeasureText(myTextView.Text, 0, myTextView.Text.Length) / metrics.Density);
// and finally formating based of if the text fits (again, specific)
if (textLength > limit)
{
myTextView.Text = myTextView.Text.Substring(0, myTextView.Text.IndexOf("-"));
}
It's pretty simple approach now that I look at it, but I'll just leave it here and maybe someone will find it useful.

How to find the position of a single word of text in a form C#

I'm not sure if this is possible or not. I'm interested in being able to find the (x,y) position of a word of text on a WinForm.
For example, in the picture below, I want to be able to pull the (x,y) coordinate of the upper-left hand corner of the letter H in "HERE".
I know how to get the position of textbox, so I can make a rough estimate based off of where the word "HERE" is inside the textbox, but I would like to be able to just ask the program where the word is if that is possible.
Also, if there is a way to get that position, I'd like to be able to get the length and height of the word (Basically I want to know the coordinates of the bounding box of the word "HERE" if possible)
Not sure if this matters, but the textbox is a richTextBox, and the textbox is populated from a string array in the Form1 class.
Thank you in advance!
You can use GetPositionFromCharIndex method, to get position of "HERE" within the TextBox or RichTextBox (it works for both).
As you probably know, to get position in the window you have to sum this up with position of your richTextBox. Like this:
int index = richTextBox1.Text.IndexOf("HERE");
Point textBoxLocation = richTextBox1.GetPositionFromCharIndex(index);
Point windowsLocation = new Point(richTextBox1.Location.X + textBoxLocation.X, richTextBox1.Location.Y + textBoxLocation.Y);
Console.WriteLine("Position in textbox: " + textBoxLocation.ToString());
Console.WriteLine("Position in window: " + windowsLocation.ToString());

Richtextbox - scroll only if scrollbar is at bottom

I have a RichTextBox and it scrolls with every AppendText, but it shall only scroll if the scrollbar is at bottom. I would like for example to easily select and copy something from the middle of the richtextbox while text is appended to the RichTextBox. Tried many solutions, but nothing really worked correct. Is this even possible?
It depends how you are Appending, but you can tell it to focus back to where the selection (or just cursor) is after appending.
eg (untested, assuming WinForms):
int selStart = rtb.SelectionStart
int selLength = rtb.SelectionLength
rtb.AppendText("test")
rtb.SelectionStart = selStart
rtb.SelectionLength = selLength
That will always push the selection back to where it was before the append - but won't scroll down if it was at the bottom previously. To me, that seems like expected behaviour.

Scroll to Position in RichTextBox

I need help in scrolling to highlighted text/string positions in a rich text box. I was able to find text and highlight it but I want the user to be able to click on a Next button and that event to scroll to the vertical offset position of the first occurrence of the highlighted word to the next and so on after each click. Any help specifically with finding the position for the vertical offset of the line of the highlighted text would be helpful as well. Thanks in advance.
I found an answer to a similar question here. Below is the code that I believe will do the trick for you.
TextPointer start = txtEditor.Selection.Start;
FrameworkContentElement fce = (start.Parent as FrameworkContentElement);
if (fce != null)
{
fce.BringIntoView();
}
I had two TextPointers with which I created a TextRange, then used .ApplyPropertyValue on that to set background colour. Then I tried...
var fce = fromTextPointer as FrameworkContentElement;
if (fce != null)
fce.BringIntoView(); // unreliable
...but it was unreliable. What I eventually discovered worked - ostensibly reliably - was using the .Start of the TextRange I created from the same fromTextPointer:
var fce = textRange.Start.Parent as FrameworkContentElement;
if (fce != null)
fce.BringIntoView(); // ostensibly reliable
I would guess that certain actions - possibly the creation of a TextRange but more likely invocation of .ApplyPropertyValue - trigger enough position normalisation within the widget and/or textRange object that the .BringIntoView() is then reliable.
Perhaps this isn't necessary for the Selection - as in Wards answer - but I wasn't manipulating the Selection and this question doesn't mention the Selection specifically either, so posting here in-case it helps some other poor soul avoid hours of WPF "fun".

Categories