Keep TextBox scroll position when adding row

In my WinForm application, I have a multi-line TextBox control (uiResults) that is used to report the progress of processing a large number of elements. Using AppendText is great for automatically scrolling from the bottom with every update, but if the user scrolls back to read some old data, I need to disable autoscrolling. I would prefer to avoid P / Invoke calls if possible.

Is it possible to determine if a user scrolls without using P / Invoke? For now, I'm just checking SelectionStart, which works, but requires the user to move the caret from the end of the text box to stop auto-scrolling:

if(uiResults.SelectionStart == uiResults.Text.Length) { uiResults.AppendText(result + Environment.NewLine); } 

My main problem is that when adding a line using the Text property, the text field scrolls to the beginning. I tried to solve this problem by preserving the carriage position and resetting it and scrolling it after updating, but this leads to the current line moving to the bottom (of course, since ScrollToCaret scrolls no more than the required distance to display the carriage).

 [Continued from above] else { int pos = uiResults.SelectionStart; int len = uiResults.SelectionLength; uiResults.Text += result + Environment.NewLine; uiResults.SelectionStart = pos; uiResults.SelectionLength = len; uiResults.ScrollToCaret(); } 
+8
source share
3 answers

Auto scroll text box uses more memory than expected

The code in the question implements exactly what you are looking for. Text is added, but scrolling occurs only if the scroll bar is at the very bottom.

+3
source

You are open to a different approach, because you will certainly encounter such problems, and the solutions will be difficult (pinvoke, etc., which you want to avoid). E.g. Suppose you find the "detect if user scroll backward" method and you stop scrolling down. But after reading the line, the user may need to resume the scroll function to the bottom. So why not give the user a way to control autoscrolling. Here's how I do it ...

Use RichTextBox to display data and a checkbox for controlling AutoScrolling, then your code might look something like this:

  richTextBox1.AppendText(result + Environment.NewLine); if (checkBoxAutoScroll.Checked) { richTextBox1.SelectionStart = richTextBox1.Text.Length; richTextBox1.ScrollToCaret(); } 

RichTextBox by default will not automatically scroll to the bottom of the AppendText, so the first line will always be visible (and not just the added line). But if the user checks this box called AutoScroll, our code will then scroll richtextbox to the bottom where new lines will be shown. If the user wants to manually scroll to read the line, he must first uncheck the box.

0
source

I had the same problem. And finally, I made the easy way. (Sorry, I am not good at English.)

The key point is to get the first displayed index using the GetCharIndexFromPosition method.

 //Get current infomation int selStart = textBox.SelectionStart; int selLen = textBox.SelectionLength; int firstDispIndex = textBox.GetCharIndexFromPosition(new Point(3, 3)); //Append Text textBox.AppendText(...); //Scroll to original displayed position textBox.Select(firstDispIndex, 0); text.ScrolltoCaret(); //Restore original Selection textBox.Select(selStart, selLen); 

And, if the text box clicks, use this extension. Call textBox.Suspend () before adding text and call textBox.Resume () after adding text.

 namespace System.Windows.Forms { public static class ControlExtensions { [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool LockWindowUpdate(IntPtr hWndLock); public static void Suspend(this Control control) { LockWindowUpdate(control.Handle); } public static void Resume(this Control control) { LockWindowUpdate(IntPtr.Zero); } } } 

Hope this helps you. Thanks ~

0
source

Source: https://habr.com/ru/post/913324/


All Articles