我想有条件地防止使用带有滚动条的
SplitterPanel
中的 MouseWheel 进行滚动,但保留滚动行为(如下面的代码所示),我该怎么做?
我在代码中有这个,但它不会阻止滚动并给出奇怪的行为:
public DocForm()
{
InitializeComponent();
this.splitContainer.Panel2.MouseWheel += new MouseEventHandler(this.splitContainer_Panel2_MouseWheel);
}
private void splitContainer_Panel2_MouseWheel(object sender, MouseEventArgs e)
{
if ((ModifierKeys & Keys.Control) == Keys.Control)
{
float scaleDelta = e.Delta / SystemInformation.MouseWheelScrollDelta * 0.1f;
// Scale instead of scrolling
// ...
}
else
{
OnMouseWheel(e);
}
}
您可以在从 SplitContainer 派生的自定义控件中实现 IMessageFilter,当消息的接收者是 SplitterPanel 之一(
WM_MOUSEHWHEEL
,此处)时,抑制 WM_MOUSEHWHEEL
(以及最终的 Panel2
)。
它可能更简单(IMO),因为 SplitterPanel 类是密封的(它隐藏了其基类的许多属性)。
调用 Application.AddMessageFilter() 添加过滤器,并调用 Application.RemoveMessageFilter() 删除它:
using System.ComponentModel;
using System.Windows.Forms;
[ToolboxItem(true), DesignerCategory("code")]
public class SplitContainerNoWheel : SplitContainer, IMessageFilter {
const int WM_MOUSEWHEEL = 0x20A;
const int WM_MOUSEHWHEEL = 0x20E;
public SplitContainerNoWheel() { }
public bool PreFilterMessage(ref Message m) {
if (m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEHWHEEL) {
// Check who's the intended recipient: the filter traps all messages
if (Panel2.IsHandleCreated && m.HWnd == Panel2.Handle) return true;
}
return false;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
Application.AddMessageFilter(this);
}
protected override void OnHandleDestroyed(EventArgs e) {
Application.RemoveMessageFilter(this);
base.OnHandleDestroyed(e);
}
}
要用此替换现有的 SplitContainer,请打开父表单的 Designer.cs 文件,然后将设置为
new SplitContainer()
的字段替换为 new SplitContainerNoWheel()
(或您决定分配给此自定义控件的任何名称)
一种方法是使用
IMessageFilter在您的
MainForm
中设置一个钩子。在这里专门这样做的优点是,它可以精确定位哪些特定控件或控件类型将接受鼠标滚轮事件的特殊处理,并在应用程序级别提供此功能,而无需创建不必要的子类或自定义控件。
public partial class MainForm : Form , IMessageFilter
{
public MainForm()
{
InitializeComponent();
Application.AddMessageFilter(this);
Disposed += (sender, e) =>Application.RemoveMessageFilter(this);
}
int _debugCount = 1;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEWHEEL)
{
// 'Generically' for SplitContainer or by any control placed within one.
if (Control.FromHandle(m.HWnd) is Control control && localIsDescOfSplitContainer(control))
{
#if DEBUG
if (control is RichTextBox logger)
{
logger.AppendText($"Count : {_debugCount++}{Environment.NewLine}");
logger.ScrollToCaret();
}
#endif
if (ModifierKeys == Keys.Control)
{
int delta = (int)m.WParam >> 16;
if (delta > 0) control.Scale(new SizeF(1.1f, 1.1f));
else control.Scale(new SizeF(0.9f, 0.9f));
// Return here to suppress further actions ONLY
// for the ModifierKeys == Control case.
// m.Result = (IntPtr)1;
// return true;
}
// Or here to suppress ALL normal functioning of the scroll wheel.
m.Result = (IntPtr)1;
return true;
}
bool localIsDescOfSplitContainer(Control? aspirant)
{
while (aspirant != null)
{
if (aspirant is SplitContainer) return true;
aspirant = aspirant.Parent;
}
return false;
}
}
base.WndProc(ref m);
return false;
}
private const int WM_MOUSEWHEEL = 0x020A;
}
private const int WM_MOUSEWHEEL = 0x020A;
}
示例
在此示例中,
RichTextBox
放置在 SplitContainer.Panel2
上。滚动鼠标滚轮时,会抑制对文本框的影响。实际上,您必须拖动 VScrollBar
才能滚动文本框。
但是当 Control 键处于活动状态时,文本框的大小将会缩放。