In my WinForm application I have a multiline TextBox control (uiResults) which is used for reporting progress while processing a large number of items. Using AppendText works great for automatically scrolling to the bottom at every update, but if the user scrolls back to read some older data I need to turn off the autoscroll. I would rather stay away from P/Invoke calls if possible.
Is it possible to detect if the user has scrolled back without using P/Invoke? For now, I just check SelectionStart which works but requires the user to move the caret from the end of the textbox to stop the autoscroll:
if(uiResults.SelectionStart == uiResults.Text.Length)
{
uiResults.AppendText(result + Environment.NewLine);
}
My main problem is that when appending a string using the Text property, the textbox is scrolled to the beginning. I tried to solve this by storing the caret position and resetting and scrolling to it after the update, but this causes the current line to move to the bottom (of course, since ScrollToCaret scrolls no more than the necessary distance to bring the caret into view).
[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();
}
Auto-scrolling text box uses more memory than expected
The code in the question implements exactly what you are looking for. Text is added, but scrolling only occurs if the scroll bar is at the very bottom.
I have had the same problem. And finally, I made an easy way. (Sorry, I'm not good at English.)
key point is get the first displayed char index using 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 textbox is flicking, use this extention. 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 will help you. Thank you~
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With