internal static Native.SCROLLINFO GetCurrentScrollInfo(IntPtr handle, int direction) { var si = new Native.SCROLLINFO(); si.cbSize = (uint)Marshal.SizeOf(si); si.fMask = (uint)Native.ScrollInfoMask.SIF_ALL; Native.GetScrollInfo(handle, direction, ref si); return(si); }
private void ResetScrollInfo() { var si = new Native.SCROLLINFO(); si.cbSize = (uint)Marshal.SizeOf(si); si.fMask = (uint)Native.ScrollInfoMask.SIF_ALL; si.nPos = 0; _scrollInfo = si; ControlUtils.RepositionScroll(Handle, si, Native.SB_VERT); }
private static void BetterScroll(IntPtr handle, int pixels) { if (pixels == 0) { return; } Native.SCROLLINFO si = ControlUtils.GetCurrentScrollInfo(handle, Native.SB_VERT); si.nPos += pixels; ControlUtils.RepositionScroll(handle, si, Native.SB_VERT); }
internal static void RepositionScroll(IntPtr handle, Native.SCROLLINFO si, int direction) { // Reposition scroll Native.SetScrollInfo(handle, direction, ref si, true); // Send a WM_*SCROLL scroll message using SB_THUMBTRACK as wParam // SB_THUMBTRACK: low-order word of wParam, si.nPos high-order word of wParam IntPtr ptrWParam = new IntPtr(Native.SB_THUMBTRACK + (0x10000 * si.nPos)); IntPtr ptrLParam = new IntPtr(0); IntPtr wp = (long)ptrWParam >= 0 ? ptrWParam : (IntPtr)Native.SB_THUMBTRACK; Native.SendMessage(handle, direction == Native.SB_VERT ? Native.WM_VSCROLL : Native.WM_HSCROLL, wp, ptrLParam); }
private async Task SetScrollPositionToCorrect() { Native.SCROLLINFO si = _scrollInfo; this.SuspendDrawing(); try { await Task.Delay(20); _scrollInfo = si; ControlUtils.RepositionScroll(Handle, si, Native.SB_VERT); } finally { this.ResumeDrawing(); } }
private void rich_TextChanged(object sender, EventArgs e) { if (m_busy) return; m_busy = true; m_buffer.Text = m_active.Text; m_buffer.SelectAll(); m_buffer.SelectionColor = m_defaultColor; ControlEventArgs args = new ControlEventArgs(m_buffer); OnHighlight(args); m_buffer.SelectionStart = m_active.SelectionStart; m_buffer.SelectionLength = m_active.SelectionLength; Native.SCROLLINFO si = new Native.SCROLLINFO(); si.Size = (uint)Marshal.SizeOf(typeof(Native.SCROLLINFO)); si.Mask = Native.SIF_POS; Native.GetScrollInfo(m_active.Handle, (int)Native.SB_VERT, ref si); Native.SetScrollInfo(m_buffer.Handle, (int)Native.SB_VERT, ref si, true); uint wparam = ((uint)si.Pos << 16) + Native.SB_THUMBPOSITION; Native.SendMessage(m_buffer.Handle, Native.WM_VSCROLL, wparam, 0); Native.SendMessage(m_buffer.Handle, Native.WM_VSCROLL, Native.SB_ENDSCROLL, 0); m_busy = false; RichTextBox temp = m_active; m_active = m_buffer; m_buffer = temp; m_active.BringToFront(); m_active.Show(); m_buffer.Hide(); m_active.Focus(); }
/* * When the rtfbox is first focused after content load, it will scroll to the top automatically (or more * specifically to the cursor location, which will always be at the top after content load and before focus). * Any subsequent de-focus and refocus will not cause this behavior, even if the cursor is still at the top, * until the next content load. * This auto-scroll-to-the-top behavior doesn't align with any events, and in fact seems to just happen in * the background as soon as it feels like it. Hence this filthy hack where we keep track of the scroll * position, and then on focus we do a brief async delay to let the auto-scroll happen, then set correct * scroll position again. I don't like the "wait-and-hope" method at all, but hey... worst case, the auto- * top-scroll will still happen, and that's no worse than it was before. */ private void Workarounds_OnVScroll() { _scrollInfo = ControlUtils.GetCurrentScrollInfo(Handle, Native.SB_VERT); }