如何确定RichTextBox滚动条何时到达底部

时间:2018-09-07 18:57:55

标签: c# .net winforms scrollbar richtextbox

这是我用C#编写的第一个代码,也是我对Stackoverflow的第一个问题...如果我做错了一切,请提前道歉! :-/

我试图实现由LarsTech编写的Public Class RTFScrolledToBottom,该问题在此处回答如下: Get current scroll position from rich text box control?

在公共Form1()代码块中,此行生成CS1061错误:

rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;

object不包含ScrolledToBottom的定义,并且找不到可访问的扩展方法ScrolledToBottom接受类型为object的第一个参数(您是否缺少using指令?还是程序集引用?)

在此先感谢您为我提供帮助,以帮助我解决问题!

干杯!

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private object rtfScrolledBottom1;

        public Form1()
        {
            InitializeComponent();
            int rtfScrolledBottom1_ScrolledToBottom = 0;
            rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {

        }
    }



    public class RTFScrolledBottom : RichTextBox
    {
        public event EventHandler ScrolledToBottom;

        private const int WM_VSCROLL = 0x115;
        private const int WM_MOUSEWHEEL = 0x20A;
        private const int WM_USER = 0x400;
        private const int SB_VERT = 1;
        private const int EM_SETSCROLLPOS = WM_USER + 222;
        private const int EM_GETSCROLLPOS = WM_USER + 221;

        [DllImport("user32.dll")]
        private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

        public bool IsAtMaxScroll()
        {
            int minScroll;
            int maxScroll;
            GetScrollRange(this.Handle, SB_VERT, out minScroll, out maxScroll);
            Point rtfPoint = Point.Empty;
            SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref rtfPoint);

            return (rtfPoint.Y + this.ClientSize.Height >= maxScroll);
        }

        protected virtual void OnScrolledToBottom(EventArgs e)
        {
            if (ScrolledToBottom != null)
                ScrolledToBottom(this, e);
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (IsAtMaxScroll())
                OnScrolledToBottom(EventArgs.Empty);

            base.OnKeyUp(e);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
            {
                if (IsAtMaxScroll())
                    OnScrolledToBottom(EventArgs.Empty);
            }

            base.WndProc(ref m);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您已将rtfScrolledBottom1定义为object,而object没有任何事件。您需要将其定义为RTFScrolledBottom。您还可以从工具箱中删除RTFScrolledBottom控件的实例,并像其他任何控件一样使用它。

替代解决方案

作为在链接的文章中找到的解决方案的替代方法,这是另一种可以与RichTextBox一起使用而无需创建派生控件的解决方案,同时您可以将逻辑放在派生控件中并使其更可重用,就像链接帖子中所做的一样。

您可以处理RichTextBox的{​​{3}}事件,并通过调用VScroll方法获得滚动位置。然后在GetScrollInfo中,如果nPage + nPos == nMax,则表示滚动位于底部:

[StructLayout(LayoutKind.Sequential)]
struct SCROLLINFO {
    public int cbSize;
    public ScrollInfoMask fMask;
    public int nMin;
    public int nMax;
    public uint nPage;
    public int nPos;
    public int nTrackPos;
}
public enum ScrollInfoMask : uint {
    SIF_RANGE = 0x1,
    SIF_PAGE = 0x2,
    SIF_POS = 0x4,
    SIF_DISABLENOSCROLL = 0x8,
    SIF_TRACKPOS = 0x10,
    SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
[DllImport("user32.dll")]
private static extern bool GetScrollInfo(IntPtr hwnd, SBOrientation fnBar, 
    ref SCROLLINFO lpsi);
public enum SBOrientation : int { SB_HORZ = 0x0, SB_VERT = 0x1 }

private void richTextBox1_VScroll(object sender, EventArgs e)
{
    var info = new SCROLLINFO() { 
        cbSize = (Marshal.SizeOf<SCROLLINFO>()),
        fMask = ScrollInfoMask.SIF_ALL 
    };
    GetScrollInfo(richTextBox1.Handle, SBOrientation.SB_VERT, ref info);
    if (info.nPage + info.nPos == info.nMax)
    {
        //VScroll is at bottom
    }
}