我有一个标签,它根据 RichTextBox 上的文本标记行号。我已经挂钩了 Vscroll 事件来处理标签。
private void rtbLogicCode_VScroll(object sender, EventArgs e)
{
Point pt = new Point(0, 1);
int firstIndex = rtbLogicCode.GetCharIndexFromPosition(pt);
int firstLine = rtbLogicCode.GetLineFromCharIndex(firstIndex);
pt.X = ClientRectangle.Width;
pt.Y = ClientRectangle.Height;
int lastIndex = rtbLogicCode.GetCharIndexFromPosition(pt);
int lastLine = rtbLogicCode.GetLineFromCharIndex(lastIndex);
// Small correction
if (rtbLogicCode.Text.EndsWith("\n"))
lastLine++;
labelLogicCode.ResetText();
LabelLineNum(firstLine+1,lastLine);
}
#endregion
private void LabelLineNum(int startNum, int lastNum)
{
labelLogicCode.Font = UIConstant.DDCLogicCodeFont;
for (int i = startNum; i < lastNum; i++)
{
labelLogicCode.Text += i + Environment.NewLine;
}
}
一切似乎都工作正常,除了 RichTextBox 使用平滑滚动功能,这在许多情况下会搞乱我的行编号,因为用户没有一直滚动到下一行。这会导致行号与 RichTextBox 上显示的实际文本不同步。
最后,我需要禁用平滑滚动功能才能完成此任务。有人告诉我可以重写 RichTextBox 的 postMessage API 来禁用上述功能,但在搜索了很多文档后,我找不到任何好的文档。
我希望有一个尽可能详细地说明如何禁用平滑滚动功能的解决方案。谢谢。
这里有一个来自 Microsoft 的 VB 示例,建议您需要拦截
WM_MOUSEWHEEL
消息。
这是一个 C# 快速原型:
class MyRichTextBox : RichTextBox {
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(
IntPtr hWnd, // handle to destination window
uint Msg, // message
IntPtr wParam, // first message parameter
IntPtr lParam // second message parameter
);
const uint WM_MOUSEWHEEL = 0x20A;
const uint WM_VSCROLL = 0x115;
const uint SB_LINEUP = 0;
const uint SB_LINEDOWN = 1;
const uint SB_THUMBTRACK = 5;
private void Intercept(ref Message m) {
int delta = (int)m.WParam >> 16 & 0xFF;
if((delta >> 7) == 1) {
SendMessage(m.HWnd, WM_VSCROLL, (IntPtr)SB_LINEDOWN, (IntPtr)0);
} else {
SendMessage(m.HWnd, WM_VSCROLL, (IntPtr)SB_LINEUP, (IntPtr)0);
}
}
protected override void WndProc(ref Message m) {
switch((uint)m.Msg) {
case WM_MOUSEWHEEL:
Intercept(ref m);
break;
case WM_VSCROLL:
if(((uint)m.WParam & 0xFF) == SB_THUMBTRACK) {
Intercept(ref m);
} else {
base.WndProc(ref m);
}
break;
default:
base.WndProc(ref m);
break;
}
}
}
我知道这已经很旧了,但是如果 Dan Sporici 的 site 出现故障,我想我应该发布他出色的解决方案。 它很简单,只需复制和粘贴即可轻松工作。
class editedRichTextBox : RichTextBox
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
//this message is sent to the control when we scroll using the mouse
private const int WM_MOUSEWHEEL = 0x20A;
//and this one issues the control to perform scrolling
private const int WM_VSCROLL = 0x115;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEWHEEL)
{
int scrollLines = SystemInformation.MouseWheelScrollLines;
for (int i = 0; i < scrollLines; i++)
{
if ((int)m.WParam > 0) // when wParam is greater than 0
SendMessage(this.Handle, WM_VSCROLL, (IntPtr)0, IntPtr.Zero); // scroll up
else
SendMessage(this.Handle, WM_VSCROLL, (IntPtr)1, IntPtr.Zero); // else scroll down
}
return;
}
base.WndProc(ref m);
}
}
这将解决 VB.NET 以及 C#(使用代码转换器)。
Public Class MyRichTextBox : Inherits RichTextBox
<System.Runtime.InteropServices.DllImport("user32.dll")> Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = &H20A Then : Dim ud As IntPtr
If m.WParam.ToInt32 > 0 Then ud = 0 Else ud = 1
For i = 1 To 3 : SendMessage(Me.Handle, &H115, ud, 0) : Next
Else : MyBase.WndProc(m) : End If
End Sub
End Class