C# 如何检测鼠标点击事件(包括窗体内外)

4

是否可以在if语句中检测鼠标左/右键的点击事件(无论是表单内还是外)?如果可以,该如何实现呢?

if(MouseButtons.LeftButton == MouseButtonState.Pressed){

...

}

1
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.capture(v=vs.110).aspx - Hans Passant
4个回答

5

当用户点击表单控件外部时,它将失去焦点,您可以利用这一点。这意味着您需要使用表单控件的_Deactivate(object sender, EventArgs e)事件来实现此功能。因为该事件会在表单失去焦点并不再是活动表单时触发。假设Form1是该表单,那么事件将如下所示:

private void Form1_Deactivate(object sender, EventArgs e)
{
    // Your code here to handle this event
}

如果我在 if 语句中说,并且如果我理解它的作用,我们无法识别点击类型。感谢您的回答。 - Hell Protection
@HellProtection:我可能误解了您的要求。您所说的“在表单外单击”是什么意思?例如,单击开始菜单吗? - sujith karivelil
我只想检测鼠标点击是否一直按住,无论在哪里(我说“窗体外面”但是我的意思是“不仅仅在内部”)。例如,在我的背景上单击。 - Hell Protection

5
如果我正确理解了你需要"从窗口外单击"的需求,而Hans Passant的建议又不符合你的需求,那么这里有一个起点。你可能需要为Form1_Click添加一个事件处理程序。
注意:此代码提供给您以说明概念。此示例中的线程同步不是100%正确的。请查看此答案的历史记录,尝试更多“线程正确”的方法,有时会引发异常。作为替代方案,为了消除所有线程问题,你可以将StartWaitingForClickFromOutside中的任务始终运行(即始终处于“监听”模式),而不是尝试检测“在表单内”或“在表单外”的状态并相应地启动/停止循环。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.MouseLeave += Form1_MouseLeave;
            this.Leave += Form1_Leave;
            this.Deactivate += Form1_Deactivate;
            this.MouseEnter += Form1_MouseEnter;
            this.Activated += Form1_Activated;
            this.Enter += Form1_Enter;
            this.VisibleChanged += Form1_VisibleChanged;
        }

        private AutoResetEvent are = new AutoResetEvent(false);

        // You could create just one handler, but this is to show what you need to link to
        private void Form1_MouseLeave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
        private void Form1_Leave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
        private void Form1_Deactivate(object sender, EventArgs e) => StartWaitingForClickFromOutside();
        private void StartWaitingForClickFromOutside()
        {
            are.Reset();
            var ctx = new SynchronizationContext();

            var task = Task.Run(() =>
            {
                while (true)
                {
                    if (are.WaitOne(1)) break;
                    if (MouseButtons == MouseButtons.Left)
                    {
                        ctx.Send(CLickFromOutside, null);
                        // You might need to put in a delay here and not break depending on what you want to accomplish
                        break;
                    }
                }
            });
        }

        private void CLickFromOutside(object state) => MessageBox.Show("Clicked from outside of the window");
        private void Form1_MouseEnter(object sender, EventArgs e) => are.Set();
        private void Form1_Activated(object sender, EventArgs e) => are.Set();
        private void Form1_Enter(object sender, EventArgs e) => are.Set();
        private void Form1_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible) are.Set();
            else StartWaitingForClickFromOutside();
        }
    }
}

如果我理解错误了你的意思,你可能会发现这个链接有用:将子控件的点击事件传递给父控件

我收到了异常:对象同步方法被从未同步的代码块调用。 - Kamlesh
@Kamlesh 很久以前写的。在哪一行? - Alexandru Clonțea

0
一种方法是使用无边框窗体覆盖整个屏幕,将属性设置为透明(略高于完全透明的几个百分点,不确定完全透明是否有效,但您不会注意到差异),并设置为最顶层。然后使用窗体的事件。一旦检测到单击,这将不会影响窗体下面的任何内容(在我的应用程序中,这是我想要发生的事情),但可以关闭窗体,然后在稍后的一小部分时间内模拟另一个鼠标单击以激活位于下方的控件。我没有问题使用Windows API在VB6中使用鼠标钩子,但似乎找不到在c#和.NET 2019版本中有效的东西,因此这是一个很好的解决方法。当然,要真正聪明,您可以使用不规则形式的方法使透明窗体与鼠标相同的形状并跟随它移动。 注意:我刚刚找到了使用钩子完成它的完整代码,普通人可以立即运行!KeyboardMouseHooks C# Library - CodePlex Archive PS如果您使用我的(愚蠢的)方法,请记得创建一个退出键或按钮,否则除非窗体被编程为对真实点击消失,否则您将不得不重新启动计算机!

你好,欢迎来到SO!请阅读tour如何撰写优秀答案?。例如,代码片段可能会有所帮助。 - Tomer Shetah

0

我知道可能有点晚了,但希望能对某些人有所帮助。使用任何控件的MouseUp事件的MouseEventArgs,您可以检查鼠标按钮和滚轮等其他信息。以下是一个示例。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.MouseUp += Form1_MouseUp;
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        if(e.Button == MouseButtons.Left)
        {
            DoSomething_LeftClick();
        }
        else if(e.Button == MouseButtons.Right)
        {
            DoSomething_RightClick();
        }
    }

    private void DoSomething_LeftClick()
    {
        //Here some code
    }
    private void DoSomething_RightClick()
    {
        //Here some code
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接