获取 Winforms 文本框的滚动条滚动值 (C#)

Get the value of a scrollbar's scroll for a Winforms Text Box (C#)

我正在使用 C# 创建一个 Windows 表单应用程序

我需要一个复选框在用户滚动到文本框底部之前显示为灰色。

如何获取文本框滚动条位置的值?

这是一个告诉您最后一行是否可见的函数:

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

您仍然需要检测滚动事件本身。请参阅 here 了解如何检测滚动。

这应该是一个 RichTextBox,因此您可以使用其 SelectionProtected 属性 来确保用户无法更改文本。它没有滚动事件,但可以通过覆盖 WndProc() 并检测 WM_VSCROLL 消息来添加。除非 WordWrap 属性 设置为 False,否则检查最后一行是否像 @TaW 那样可见是不可靠的。更容易检查滚动条的状态。

向您的项目添加一个新的 class 并粘贴如下所示的代码。编译。将工具箱顶部的新控件拖放到窗体上。订阅 LicenseViewed 事件并将复选框“已启用 属性 设置为 true。如果我不指出只有律师才认为这是个好主意,那我就失职了,用户发现这类文本框普遍令人讨厌并且非常讨厌它们。您只有一次机会创造良好的第一印象。

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

}