文本框或RichTextBox的,只有我想的事情是触发功能移动滚动条时。
我已经找到GetScrollPos和SetScrollPos。 我想定期检查滚动条的位置,但必须有一个更好的办法。 那么,什么是更好的办法?
更新:使用的WinForms
文本框或RichTextBox的,只有我想的事情是触发功能移动滚动条时。
我已经找到GetScrollPos和SetScrollPos。 我想定期检查滚动条的位置,但必须有一个更好的办法。 那么,什么是更好的办法?
更新:使用的WinForms
假设的WinForms,你可以尝试pinvoking:
public class MyRTF: RichTextBox {
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if (m.Msg == WM_VSCROLL || m.Msg == WM_HSCROLL || m.Msg == WM_MOUSEWHEEL) {
// scrolling...
}
}
}
改编接受的答案,包括horizontalScrollPosition和verticalScrollPosition属性(获取和设置滚动位置)和ScrollChanged事件(使用.NET的ScrollEventArgs)。 ScrollChanged也会开火键导航和文字修改,以及选择拖动,控制调整大小和字体大小调整期间。
/// <summary>
/// TextBox with support for getting and setting the vertical scroll bar
/// position, as well as listening to vertical scroll events.
/// </summary>
public class ScrollTextBox : System.Windows.Forms.TextBox
{
public ScrollTextBox()
{ _components = new System.ComponentModel.Container();
// Calculate width of "W" to set as the small horizontal increment
OnFontChanged(null);
}
[ System.ComponentModel.DefaultValue(0)
, System.ComponentModel.Category("Appearance")
, System.ComponentModel.Description
( "Gets or sets the vertical scroll bar's position"
)
]
public int VerticalScrollPosition
{ set { SetScroll(value, Win32.WM_VSCROLL, Win32.SB_VERT); }
get { return GetScroll(Win32.SB_VERT); }
}
[ System.ComponentModel.DefaultValue(0)
, System.ComponentModel.Category("Appearance")
, System.ComponentModel.Description
( "Gets or sets the horizontal scroll bar's position"
)
]
public int HorizontalScrollPosition
{ set { SetScroll(value, Win32.WM_HSCROLL, Win32.SB_HORZ); }
get { return GetScroll(Win32.SB_HORZ); }
}
[ System.ComponentModel.Description
( "Fired when the scroll bar's vertical position changes"
)
, System.ComponentModel.Category("Property Changed")
]
public event System.Windows.Forms.ScrollEventHandler ScrollChanged;
// Fire scroll event if the scroll-bars are moved
protected override void WndProc
( ref System.Windows.Forms.Message message
){ base.WndProc(ref message);
if(message.Msg == Win32.WM_VSCROLL
|| message.Msg == Win32.WM_HSCROLL
|| message.Msg == Win32.WM_MOUSEWHEEL
) TryFireScrollEvent();
}
// Key-down includes navigation keys, but also typing and pasting can
// cause a scroll event
protected override void OnKeyDown
( System.Windows.Forms.KeyEventArgs e
){ base.OnKeyDown(e);
TryFireScrollEvent();
}
protected override void OnKeyUp
( System.Windows.Forms.KeyEventArgs e
){ base.OnKeyUp(e);
TryFireScrollEvent();
}
// Resizing can alter the word-wrap or fit the content causing the text
// to scroll
protected override void OnResize
( System.EventArgs e
){ base.OnResize(e);
TryFireScrollEvent();
}
// Clicking an empty space can move the carot to the beginning of the
// line causing a scroll event
protected override void OnMouseDown
( System.Windows.Forms.MouseEventArgs e
){ base.OnMouseDown(e);
TryFireScrollEvent();
}
protected override void OnMouseUp
( System.Windows.Forms.MouseEventArgs e
){ base.OnMouseUp(e);
TryFireScrollEvent();
}
// If the mouse button is down, a text selection is probably being done
// where dragging the selection can caues scroll events
protected override void OnMouseMove
( System.Windows.Forms.MouseEventArgs e
){ base.OnMouseMove(e);
if(e.Button != System.Windows.Forms.MouseButtons.None)
TryFireScrollEvent();
}
// Changing the size of the font can cause a scroll event. Also, when
// scrolling horizontally, the event will notify whether the scroll
// was a large or small change. For vertical, small increments are 1
// line, but for horizontal, it is several pixels. To guess what a
// small increment is, get the width of the W character and anything
// smaller than that will be represented as a small increment
protected override void OnFontChanged
( System.EventArgs e
){ base.OnFontChanged(e);
using(System.Drawing.Graphics graphics = this.CreateGraphics())
_fontWidth = (int)graphics.MeasureString("W", this.Font).Width;
TryFireScrollEvent();
}
protected override void Dispose
( bool disposing
){ if(disposing && (_components != null))
_components.Dispose();
base.Dispose(disposing);
}
private void SetScroll
( int value
, uint windowsMessage
, int scrollBarMessage
){ Win32.SetScrollPos
( (System.IntPtr)this.Handle
, scrollBarMessage
, value
, true
);
Win32.PostMessage
( (System.IntPtr)this.Handle
, windowsMessage
, 4 + 0x10000 * value
, 0
);
}
private int GetScroll
( int scrollBarMessage
){ return Win32.GetScrollPos
( (System.IntPtr)this.Handle
, scrollBarMessage
);
}
// Fire both horizontal and vertical scroll events seperately, one
// after the other. These first test if a scroll actually occurred
// and won't fire if there was no actual movement
private void TryFireScrollEvent()
{ // Don't do anything if there is no event handler
if(ScrollChanged == null)
return;
TryFireHorizontalScrollEvent();
TryFireVerticalScrollEvent();
}
private void TryFireHorizontalScrollEvent()
{
// Don't do anything if there is no event handler
if(ScrollChanged == null)
return;
int lastScrollPosition = _lastHorizontalScrollPosition;
int scrollPosition = HorizontalScrollPosition;
// Don't do anything if there was no change in position
if(scrollPosition == lastScrollPosition)
return;
_lastHorizontalScrollPosition = scrollPosition;
ScrollChanged
( this
, new System.Windows.Forms.ScrollEventArgs
( scrollPosition < lastScrollPosition - _fontWidth
? System.Windows.Forms.ScrollEventType.LargeDecrement
: scrollPosition > lastScrollPosition + _fontWidth
? System.Windows.Forms.ScrollEventType.LargeIncrement
: scrollPosition < lastScrollPosition
? System.Windows.Forms.ScrollEventType.SmallDecrement
: System.Windows.Forms.ScrollEventType.SmallIncrement
, lastScrollPosition
, scrollPosition
, System.Windows.Forms.ScrollOrientation.HorizontalScroll
)
);
}
private void TryFireVerticalScrollEvent()
{
// Don't do anything if there is no event handler
if(ScrollChanged == null)
return;
int lastScrollPosition = _lastVerticalScrollPosition;
int scrollPosition = VerticalScrollPosition;
// Don't do anything if there was no change in position
if(scrollPosition == lastScrollPosition)
return;
_lastVerticalScrollPosition = scrollPosition;
ScrollChanged
( this
, new System.Windows.Forms.ScrollEventArgs
( scrollPosition < lastScrollPosition - 1
? System.Windows.Forms.ScrollEventType.LargeDecrement
: scrollPosition > lastScrollPosition + 1
? System.Windows.Forms.ScrollEventType.LargeIncrement
: scrollPosition < lastScrollPosition
? System.Windows.Forms.ScrollEventType.SmallDecrement
: System.Windows.Forms.ScrollEventType.SmallIncrement
, lastScrollPosition
, scrollPosition
, System.Windows.Forms.ScrollOrientation.VerticalScroll
)
);
}
private int _lastVerticalScrollPosition;
private int _lastHorizontalScrollPosition;
private int _fontWidth;
private System.ComponentModel.IContainer _components = null;
private static class Win32
{
public const uint WM_HSCROLL = 0x114;
public const uint WM_VSCROLL = 0x115;
public const uint WM_MOUSEWHEEL = 0x20A;
public const int SB_VERT = 0x1;
public const int SB_HORZ = 0x0;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SetScrollPos
( System.IntPtr hWnd
, int nBar
, int nPos
, bool bRedraw
);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int GetScrollPos
( System.IntPtr hWnd
, int nBar
);
[ System.Runtime.InteropServices.DllImport
( "User32.Dll"
, EntryPoint = "PostMessageA")
]
public static extern bool PostMessage
( System.IntPtr hWnd
, uint msg
, int wParam
, int lParam
);
}
}
更妙的是-隐藏的MouseWheel
事件: https://stackoverflow.com/a/26672097/1037948
public Form1()
{
InitializeComponent();
textBox1.MouseWheel += textBox1_MouseWheel;
}
void textBox1_MouseWheel(object sender, MouseEventArgs e)
{
throw new NotImplementedException();
}