Jak zapobiec automatycznemu przewijaniu TextBox podczas dołączania tekstu?
Mam wielowierszowy TextBox z pionowym paskiem przewijania, który rejestruje dane z procesu w czasie rzeczywistym. Obecnie za każdym razem, gdy dodawana jest nowa liniatextBox.AppendText()
, TextBox przewija do dołu, dzięki czemu można zobaczyć ostatni wpis, to świetnie. Ale mam pole wyboru, aby zdecydować, kiedy TextBox ma zezwolenie na automatyczne przewijanie. Czy i tak to zrobić?
Uwaga:
Chcę używać TextBox, ponieważ dodany tekst ma wiele linii i jest sformatowany przez białe spacje, więc nie jest prosty w użyciu z ListBox lub ListView.Próbowałem dodać nową linię wedługtextBox.Text += text
, ale TextBox zawsze przewija do góry.Jeśli mamy rozwiązanie, to kolejne pytanie brzmi: jak zapobiec automatycznemu przewijaniu TextBox, gdy użytkownik korzysta z paska przewijania, aby zobaczyć gdzieś w polu tekstowym, gdy TextBox dołącza tekst?
private void OnTextLog(string text)
{
if (chkAutoScroll.Checked)
{
// This always auto scrolls to the bottom.
txtLog.AppendText(Environment.NewLine);
txtLog.AppendText(text);
// This always auto scrolls to the top.
//txtLog.Text += Environment.NewLine + text;
}
else
{
// I want to append the text without scrolls right here.
}
}
Aktualizacja 1: Tak jaksaggio sugeruje, uważam też, że rozwiązaniem tego problemu jest określenie pozycji pierwszego znaku w bieżącym tekście wyświetlanego w TextBox przed dołączeniem tekstu i przywrócenie go po tym. Ale jak to zrobić? Próbowałem nagrać bieżącą pozycję kursora w ten sposób, ale to nie pomogło:
int selpoint = txtLog.SelectionStart;
txtLog.AppendText(Environment.NewLine);
txtLog.AppendText(text);
txtLog.SelectionStart = selpoint;
Aktualizacja 2 (problem został rozwiązany): Znalazłemrozwiązanie to może rozwiązać mój problem tutaj na Stack Overflow. Zoptymalizowałem ich kod, aby pasował do mojego problemu w następujący sposób:
// Constants for extern calls to various scrollbar functions
private const int SB_VERT = 0x1;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 0x4;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
private void AppendTextToTextBox(TextBox textbox, string text, bool autoscroll)
{
int savedVpos = GetScrollPos(textbox.Handle, SB_VERT);
textbox.AppendText(text + Environment.NewLine);
if (autoscroll)
{
int VSmin, VSmax;
GetScrollRange(textbox.Handle, SB_VERT, out VSmin, out VSmax);
int sbOffset = (int)((textbox.ClientSize.Height - SystemInformation.HorizontalScrollBarHeight) / (textbox.Font.Height));
savedVpos = VSmax - sbOffset;
}
SetScrollPos(textbox.Handle, SB_VERT, savedVpos, true);
PostMessageA(textbox.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
private void OnTextLog(string text)
{
AppendTextToTextBox(txtLog.Text, Environment.NewLine + text, chkAutoScroll.Checked);
}
Inny sposób:
private const int SB_VERT = 0x1;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 0x4;
private const int SB_BOTTOM = 0x7;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
private void AppendTextToTextBox(TextBox textbox, string text, bool autoscroll)
{
int savedVpos = GetScrollPos(textbox.Handle, SB_VERT);
textbox.AppendText(text + Environment.NewLine);
if (autoscroll)
{
PostMessageA(textbox.Handle, WM_VSCROLL, SB_BOTTOM, 0);
}
else
{
SetScrollPos(textbox.Handle, SB_VERT, savedVpos, true);
PostMessageA(textbox.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
}
Zamieszczam te rozwiązania dla tych, którzy mają podobny problem. Dzięki zacgyDeveloperkod źródłowy.
Czy ktoś ma prostszy sposób?