9

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();
}

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

WM_VSCROLL is fired when the vertical scroll bar is moved and is NOT fired via AppendText. Is there different message to catch?
@Brad Rem. Didn't understand your full question. Updated.
2

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~

Comments

0

Are you open to another approach, because you are bound to get into trouble this way and the solutions will get complex (pinvoke etc. that you want to avoid). For eg. suppose you find a way to "detect if the user has scrolled back" and you stop scrolling to bottom. But after reading the line user might want the scroll to bottom feature to resume. So why not give user a way to control Auto-Scrolling. Here's how I would do it...

Use a RichTextBox to show data and a Checkbox to control AutoScrolling, then your code might be 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 bottom on AppendText, so the first line would always be visible (and not the newly appended line). But if user checks this checkbox called AutoScroll, our code will then scroll the richtextbox to the bottom where new lines are shown. If user wants to manually scroll to read a line he will first need to uncheck the checkbox.

1 Comment

Unfortunately, it seems like also the RichTextBox scrolls to the bottom when using AppendText - but only when the control have focus. But since the users sometimes need to select and copy text, this approach sadly won't work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.