Winforms 为什么GroupBox没有MouseMove事件?

Winforms 为什么GroupBox没有MouseMove事件?,winforms,mouseevent,groupbox,Winforms,Mouseevent,Groupbox,WinForms GroupBox控件不支持MouseMove(或者至少不一致),我不明白为什么 由于它是从控件派生的,因此它确实有一个MouseMove事件,但是GroupBox使用Browsable(false)显式地重新引入它,因此它不会显示在属性网格中。您可以在运行时钩住MouseMove事件,有时它可以工作——只要FlatStyle保持在标准状态。如果GroupBox的FlatStyle设置为System,则根本不会触发MouseMove事件 反射器没有给我任何线索。GroupBox构

WinForms GroupBox控件不支持MouseMove(或者至少不一致),我不明白为什么

由于它是从控件派生的,因此它确实有一个MouseMove事件,但是GroupBox使用
Browsable(false)
显式地重新引入它,因此它不会显示在属性网格中。您可以在运行时钩住MouseMove事件,有时它可以工作——只要FlatStyle保持在标准状态。如果GroupBox的FlatStyle设置为System,则根本不会触发MouseMove事件

反射器没有给我任何线索。GroupBox构造函数似乎没有设置任何奇怪的控件样式,GroupBox也没有做任何愚蠢的事情,比如重写MouseMove和调用base失败

这似乎也是WinForms特有的限制,因为Delphi组框对OnMouseMove的支持很好。更正:与Delphi的比较无效。Delphi组框实际上不是标准的BM_组框控件;它们只是被绘制成类似于组框的外观,实际上没有继承像这样奇怪的组框行为。所以这很可能是Windows groupbox控件的一个限制,尽管我还没有在任何地方看到它的文档


为什么WinForms GroupBox不支持MouseMove?

您可以通过Reflector看到这一点,键属性是CreateParams,内部OwnerDraw属性。GroupBox通常在OwnerDraw=true的情况下运行,除非设置FlatStyle=System。然后您会得到一个老式的Windows组框,一个类名为BUTTON的窗口,打开了BS_GROUPBOX样式位

如果您使用Spy++,您将看到该控件根本没有收到任何鼠标消息。不知道为什么会这样,SDK文档没有提到它。我想这可以追溯到Windows2.x,在那里每个周期都有计数。但它确实解释了为什么MouseMove事件是隐藏的,当选择系统样式时它不能触发。单击和向上/向下操作也一样。FlatStyle属性设置程序还关闭了Control.UserMouse控件样式,从而真正解决了这个问题

总之,如果您想要鼠标消息,您需要避免使用系统样式。

根据,标准Windows groupbox(即具有BS_groupbox样式的按钮控件)会返回HTTRANSPARENT以响应WM_NCHITTEST。由于控件声称是透明的,Windows将鼠标移动事件发送到其父窗口

线程确认,如果您自己处理WM_NCHITTEST并返回HTCLIENT,那么groupbox将获得鼠标移动事件。他们正在使用MFC,但它可能也适用于WinForms


目前尚不清楚的是Windows默认返回HTTRANSPARENT的原因,但至少问题已经得到独立确认。

组框是一个静态控件,其中包含其他控件。它的设计纯粹是为了将事物“组合”在一起,以使用户界面在布局正确的情况下更直观。因此,可以代表GroupBox使用的事件很少

您可以创建一个从GroupBox继承的新类,并将其子类化以拦截鼠标移动事件。我以前使用过一个非常有用的类,执行子类化和触发MouseMove事件非常容易

看看这个,看看子类是如何工作的……好吧,它是用VB.NET编写的,但是很容易将它翻译成C#如果你愿意的话,我想象的代码是这样的: 注意:我包含的这段代码是我脑海中最重要的部分,所以这段代码中可能有错误……但这就是它的要点

编辑:为了回应乔·怀特的评论,我加入了修改后的代码,它确实发送了WM_MOUSEMOVE…看看下面的步骤,我是如何在VS 2008 Pro下复制的

public class MyGroupBox : System.Windows.Forms.GroupBox { private SubClass sc; private const int WM_MOUSEMOVE = 0x200; public delegate void MyMouseMoveEventHandler(object sender, System.EventArgs e); public event MyMouseMoveEventHandler MyMouseMove; public MyGroupBox() : base() { sc = new SubClass(this.Handle, true); sc.SubClassedWndProc += new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc); } protected override void Dispose(bool disposing) { if (sc.SubClassed) { sc.SubClassedWndProc -= new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc); sc.SubClassed = false; } base.Dispose(disposing); } private void OnMyMouseMove() { if (this.MyMouseMove != null) this.MyMouseMove(this, System.EventArgs.Empty); } void sc_SubClassedWndProc(ref Message m) { if (m.Msg == WM_MOUSEMOVE) this.OnMyMouseMove(); } } #region SubClass Classing Handler Class public class SubClass : System.Windows.Forms.NativeWindow { public delegate void SubClassWndProcEventHandler(ref System.Windows.Forms.Message m); public event SubClassWndProcEventHandler SubClassedWndProc; private bool IsSubClassed = false; public SubClass(IntPtr Handle, bool _SubClass) { base.AssignHandle(Handle); this.IsSubClassed = _SubClass; } public bool SubClassed { get { return this.IsSubClassed; } set { this.IsSubClassed = value; } } protected override void WndProc(ref Message m) { if (this.IsSubClassed) { OnSubClassedWndProc(ref m); } base.WndProc(ref m); } #region HiWord Message Cracker public int HiWord(int Number) { return ((Number >> 16) & 0xffff); } #endregion #region LoWord Message Cracker public int LoWord(int Number) { return (Number & 0xffff); } #endregion #region MakeLong Message Cracker public int MakeLong(int LoWord, int HiWord) { return (HiWord << 16) | (LoWord & 0xffff); } #endregion #region MakeLParam Message Cracker public IntPtr MakeLParam(int LoWord, int HiWord) { return (IntPtr)((HiWord << 16) | (LoWord & 0xffff)); } #endregion private void OnSubClassedWndProc(ref Message m) { if (SubClassedWndProc != null) { this.SubClassedWndProc(ref m); } } } #endregion 到
  • 保存并编译它
  • 返回designer窗口,单击组框,在属性工具箱中查找
    MyMouseMove
    事件,并将其连接起来
  • 您的事件处理程序应该如下所示:
  • 私有void groupBox1_MyMouseMove(对象发送方,事件参数e) { System.Diagnostics.Debug.WriteLine(“MyMouseMove!”); } 运行应用程序,每次在groupbox中移动鼠标时,都会看到输出“MyMouseMove!”

    希望这能给你一个提示, 顺致敬意,
    Tom。

    我注意到某些控件的许多事件无法通过VS中的“事件”选项卡(在“属性”下)访问。您只需在父窗体的设计器中的
    InitializeComponents()下手动分配事件处理程序即可:

    这将触发以下方法:

    private void groupBox1_MouseMove(object sender, MouseEventArgs e)
    {
        //doodle the stuff you want to happen after the trigger here
    };
    

    我对此持怀疑态度,因为其他回复证实了
    WM\u MOUSEMOVE
    从未发送到groupbox。你有没有测试过这段代码是否能与GroupBox一起使用?@Joe White:请看我修改过的代码以及我使用这些代码的步骤。嗯。向您致意,Tom。我在问题中已经说过:“您可以在运行时钩住MouseMove事件,有时它可以工作——只要FlatStyle保持在标准状态。如果GroupBox的FlatStyle设置为System,则根本不会触发MouseMove事件。” WindowsApplication.MyGroupBox groupBox1; this.groupBox1 = new WindowsApplication.MyGroupBox(); private void groupBox1_MyMouseMove(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine("MyMouseMove!"); }
    this.groupBox1.MouseMove += new MouseEventHandler(this.groupBox1_MouseMove);
    
    private void groupBox1_MouseMove(object sender, MouseEventArgs e)
    {
        //doodle the stuff you want to happen after the trigger here
    };