C# 多个控件上的相同MouseMove事件

C# 多个控件上的相同MouseMove事件,c#,C#,我有一个用户控件,其中包含一个填充整个UC的面板。面板内有一个PctureBox和一个标签。我的问题是,无论光标在哪个控件上移动,面板上的背景色都会作为指示器改变。我已经用这种方式实现了这一点(请参阅下面的代码),但我确信这不是最好的方式?请记住,我将添加大约一百个,所以我的目标是对其进行相当优化 private void PMain_MouseMove(object sender, MouseEventArgs e) { Panel pan = sender as Panel;

我有一个用户控件,其中包含一个填充整个UC的面板。面板内有一个PctureBox和一个标签。我的问题是,无论光标在哪个控件上移动,面板上的背景色都会作为指示器改变。我已经用这种方式实现了这一点(请参阅下面的代码),但我确信这不是最好的方式?请记住,我将添加大约一百个,所以我的目标是对其进行相当优化

private void PMain_MouseMove(object sender, MouseEventArgs e)
{
    Panel pan = sender as Panel;
    pan.BackColor = Color.DimGray;
}

private void PMain_MouseLeave(object sender, EventArgs e)
{
    Panel pan = sender as Panel;
    pan.BackColor = originalBackColor;
}

private void PbIcon_MouseMove(object sender, MouseEventArgs e)
{
    pMain.BackColor = Color.DimGray;
}

private void PbIcon_MouseLeave(object sender, EventArgs e)
{
    pMain.BackColor = originalBackColor;
}

private void LTitle_MouseMove(object sender, MouseEventArgs e)
{
    pMain.BackColor = Color.DimGray;
}

private void LTitle_MouseLeave(object sender, EventArgs e)
{
    pMain.BackColor = originalBackColor;
}

也许你可以这样做。例如:

设计师

//SomeButton
this.SomeButton.Click += delegate(object sender, EventArgs e) 
                    { SomeUserControl_Event(sender, e); };
//SomeLabel
this.SomeButton.Click += delegate(object sender, EventArgs e) 
                    { SomeUserControl_Event(sender, e); };
Cs


这只是一个例子

如果我理解正确,那么您正在尝试执行以下操作

为了做到这一点,而不必对用户控件拥有的每个控件都执行此操作,您可以在主线程中插入一个线程WH_GETMESSAGE钩子,并检查用户控件及其子控件的WM_MOUSEHOVER、WM_MOUSELEAVE、WM_MOUSEMOVE消息

下面是UserControl1的代码示例,它有一个填充整个UC的面板、一个PictureBox(其中有考拉)和一个标签(上面写有标签1)

使用系统;
使用系统图;
使用System.Windows.Forms;
使用System.Runtime.InteropServices;
使用系统诊断;
命名空间WindowsFormsApp1
{
公共部分类UserControl1:UserControl
{
const int WH_GETMESSAGE=0x03;
常数int WM_MOUSEHOVER=0x02A1;
常数int WM_MOUSELEAVE=0x02A3;
常量int WM_MOUSEMOVE=0x0200;
私有委托int HookProc(int代码、IntPtr wParam、IntPtr lParam);
[DllImport(“user32.dll”,EntryPoint=“SetWindowsHookEx”,SetLastError=true)]
静态外部IntPtr SETWINDOWSHOOKX(int idHook、HookProc lpfn、IntPtr hMod、uint dwThreadId);
[DllImport(“user32.dll”)]
静态外部bool unhookwindowshookx(IntPtr hHook);
[DllImport(“user32.dll”)]
静态外部int CALLNEXTHOKEX(IntPtr hhk、int nCode、IntPtr wParam、IntPtr lParam);
[DllImport(“kernel32.dll”,CharSet=CharSet.Auto)]
公共静态外部IntPtr GetModuleHandle(字符串lpModuleName);
[DllImport(“user32.dll”)]
静态外部单元GetWindowThreadProcessId(IntPtr hWnd、IntPtr lpdwProcessId);
IntPtr_钩;
HookProc_HookProc;
公共用户控制1()
{
初始化组件();
this.HandleCreated+=(发件人,e)=>
{
_hookProc=新的hookProc(GetMsgHookProc);
_hook=setWindowshookx(
你得到消息了吗,
_hookProc,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
GetWindowThreadProcessId(this.Handle,IntPtr.Zero));
};
此.Disposed+=(发送方,e)=>
{
解开钩(_钩);
};
}
私人布尔伊索希尔德(控制控制)
{
如果(ctl==null)
返回false;
if(ctl.Handle==this.Handle | | ctl.Parent?.Handle==this.Handle)
返回true;
返回IsOurChild(控制父项);
}
私有int-GetMsgHookProc(int-nCode、IntPtr-wParam、IntPtr-lParam)
{
if(nCode<0)
返回CallNextHookEx(_hook,nCode,wParam,lParam);
消息m=Marshal.PtrToStructure(lParam);
Control ctl=Control.FromHandle(m.HWnd);
如果(IsOurChild(ctl))
{
if(m.Msg==WM|MOUSEHOVER | m.Msg==WM|MOUSEMOVE)
this.BackColor=Color.Red;
如果(m.Msg==WM_MOUSELEAVE)
this.BackColor=Color.Blue;
}
返回CallNextHookEx(_hook,nCode,wParam,lParam);
}
}
}

谢谢你,@GSerg。我会调查的,看起来像是可以使用的东西。我还不完全确定如何在我的用例中使用它,但我确信我会找到它。事实上,这个GIF示例正是我想要实现的。完全正确我会尽快尝试一下,并将结果反馈给您。看起来很有希望,尽管我必须承认我并不理解所有的代码——我只是理解了它的大意。让我知道是否有什么我应该知道的,或者它是否需要任何东西,例如特定属性设置为某个值。代码的哪一部分您不理解?指出,我会尽力解释。如果你需要更详细的解释,就说,我会相应地编辑我的帖子。但您可以查看以下链接,了解win32 message loop()、win32 hook mechanism()的概念基本上有几个部分,这可能是因为我从未使用过
DllImports
,我对
hooks
messages
没有经验,但我会看看您发送的文档,我相信这会有帮助的。话虽如此,我将这段代码添加到我的用户控件中,它工作得很好,因此,我接受这一点作为答案。虽然我试图将
用户控件添加到
流程布局中,但我注意到效果不再存在。它似乎只在主窗体中直接起作用。我真的不知道在这一点上如何处理这个问题。我看看这些文档是否能让我更清楚。我已经根据你的第二个问题编辑了我的答案,你能再试一次吗。问题出在IsOurChild函数中,您可以用新的onePerfect替换它!非常感谢。这解决了问题,我可以确认它在FlowLayout中工作。我还没有测试在添加几个用户控件时它的性能,但到目前为止还不错。
private void SomeUserControl_Event(object sender, EventArgs e)
{
    pMain.BackColor = originalBackColor;
}
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace WindowsFormsApp1
{
    public partial class UserControl1 : UserControl
    {
        const int WH_GETMESSAGE = 0x03;
        const int WM_MOUSEHOVER = 0x02A1;
        const int WM_MOUSELEAVE = 0x02A3;
        const int WM_MOUSEMOVE = 0x0200;

        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hHook);

        [DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);

        IntPtr _hook;
        HookProc _hookProc;
        public UserControl1()
        {
            InitializeComponent();

            this.HandleCreated += (sender, e) =>
            {
                _hookProc = new HookProc(GetMsgHookProc);
                _hook = SetWindowsHookEx(
                    WH_GETMESSAGE,
                    _hookProc,
                    GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                    GetWindowThreadProcessId(this.Handle, IntPtr.Zero));
            };
            this.Disposed += (sender, e) => 
            {
                UnhookWindowsHookEx(_hook);
            };
        }


        private bool IsOurChild(Control ctl)
        {
            if (ctl == null)
                return false;
            if (ctl.Handle == this.Handle || ctl.Parent?.Handle == this.Handle)
                return true;
            return IsOurChild(ctl.Parent);
        }

        private int GetMsgHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
                return CallNextHookEx(_hook, nCode, wParam, lParam);

            Message m = Marshal.PtrToStructure<Message>(lParam);
            Control ctl = Control.FromHandle(m.HWnd);
            if (IsOurChild(ctl))
            {
                if (m.Msg == WM_MOUSEHOVER || m.Msg == WM_MOUSEMOVE)
                    this.BackColor = Color.Red;
                if (m.Msg == WM_MOUSELEAVE)
                    this.BackColor = Color.Blue;
            }

            return CallNextHookEx(_hook, nCode, wParam, lParam);
        }
    }
}