Get the value of a scrollbar's scroll for a Wi

2019-09-07 06:22发布

问题:

I am creating a Windows Form Application using C#

I require a checkbox to be greyed out until the user scrolls to the bottom of a text box.

How can I get the value of the textbox's scrollbar position?

回答1:

This should be a RichTextBox so you can use its SelectionProtected property to ensure that the user cannot change the text. It does not have a Scroll event but that can be added by overriding WndProc() and detecting the WM_VSCROLL message. Checking if the last line is visible like @TaW does is not reliable unless the WordWrap property is set to False. Easier to just check the state of the scrollbar.

Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. Subscribe the LicenseViewed event and set the checkbox' Enabled property to true. I would be remiss if I did not point out that only lawyers ever think this is a good idea, users find these kind of text boxes universally annoying and hate them with a passion. You only have one chance to create a good first impression.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class LicenseBox : RichTextBox {
    public event EventHandler LicenseViewed;

    public override string Text {
        get { return base.Text; }
        set { base.Text = value;  textChanged(); }
    }

    public new string Rtf {
        get { return base.Rtf; }
        set { base.Rtf = value; textChanged(); }
    }

    private bool eventFired;

    private void textChanged() {
        this.SelectAll();
        this.SelectionProtected = true;
        this.SelectionStart = this.SelectionLength = 0;
        eventFired = false;
        checkScrollbar();
    }

    private void checkScrollbar() {
        if (eventFired || !this.IsHandleCreated) return;
        var pos = new ScrollInfo();
        pos.cbSize = Marshal.SizeOf(pos);
        pos.fMask = 7;
        if (!GetScrollInfo(this.Handle, SB_VERT, ref pos)) return;
        if (pos.nPos >= pos.nMax - pos.nPage) {
            if (LicenseViewed != null) LicenseViewed(this, EventArgs.Empty);
            eventFired = true;
        }
    }

    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL) checkScrollbar();
    }

    // Pinvoke
    private const int WM_VSCROLL = 0x115;
    private const int WM_MOUSEWHEEL = 0x20A;
    private const int SB_VERT = 1;
    private struct ScrollInfo {
        public int cbSize, fMask, nMin, nMax, nPage, nPos, nTrackPos;
    }
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool GetScrollInfo(IntPtr hwnd, int bar, ref ScrollInfo pos);

}


回答2:

Here is a function that tells you if the last line is visible:

bool LastLineVisible(TextBox textbox)
{
    Point lowPoint = new Point(3, textbox.ClientSize.Height - 3);
    int lastline = textbox.Lines.Count() - 1;
    int charOnLastvisibleLine = textbox.GetCharIndexFromPosition(lowPoint);
    int lastVisibleLine = textbox.GetLineFromCharIndex(charOnLastvisibleLine);
    return lastVisibleLine >= lastline;
}

You will still need to detect the scrolling event itself. See here on how to detect the scrolling.