问题描述
这是我在使用.NET WinForms鼠标事件时所遇到的烦恼。要进行复制,请执行以下操作:
- 将鼠标左键放在按钮控件上。 (这会将捕获控件更改为该按钮)
- 将鼠标移出该按钮。
- 在仍然按住鼠标左键的同时,单击鼠标右键。 (这会将捕获控件更改为现在鼠标指针悬停的位置)
- 释放鼠标左键。该按钮永远不会收到鼠标向上事件。 (鼠标移至当前的捕获控件。)
我只关心鼠标左键,但是用户不小心按下了鼠标右键可防止鼠标左移事件返回到最初单击的按钮。
一种可能的解决方案是使用 MouseLeave 或 MouseCaptureChanged 事件来检测何时右键单击了按钮并知道捕获控件何时更改。我已经尝试过了,效果很好。
另一种方法是使用 MessageFilters 并过滤掉右键事件。但是某些按钮需要右键单击,因此您不想仅出于需要此功能的按钮就过滤掉所有右键单击。
所以我要问是否有人知道更好的解决方案。如果Windows具有某种标志来执行以下操作,那就太好了:
button1.RightMouseButtonCanChangeMouseCapture = false;
解决方法
在我使用MessageFilter方法进行的测试中,这似乎工作得很好:
public partial class Form1 : Form
{
private MyFilter mf;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
mf = new MyFilter();
Application.AddMessageFilter(mf);
mf.MouseLeftUp += Mf_MouseLeftUp;
}
private void button1_MouseDown(object sender,MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mf.ButtonDown = true;
Console.WriteLine("Transmitting...");
}
}
private void Mf_MouseLeftUp()
{
Console.WriteLine("Transmission Stopped.");
}
}
public class MyFilter : IMessageFilter
{
public bool ButtonDown = false;
private const int WM_LBUTTONUP = 0x0202;
public event dlgMouseLeftUp MouseLeftUp;
public delegate void dlgMouseLeftUp();
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONUP:
if (ButtonDown)
{
ButtonDown = false;
MouseLeftUp?.Invoke();
}
break;
}
return false; // allow normal dispatching of messages
}
}