首页 > 解决方案 > 为什么按下鼠标按钮时 MouseMove 不会触发?

问题描述

关于 WPF 鼠标处理,我显然不明白,所以我会很感激我能得到的任何帮助。很抱歉让这个冗长 - 我被告知要提供足够的上下文信息,以便其他人可以弄清楚我想要完成什么。

我有一系列按钮,每个按钮都包含图像的预览。当放大我也显示的完整图像时,我想使用相应的预览按钮作为我实际放大的完整图像的哪一部分的指示器。为此,我使用Adorner在预览图像顶部绘制一个简单的矩形框,反映缩放区域。请参阅屏幕截图以进行说明 - 左下方的按钮显示橙色矩形中的缩放区域。

截屏

所有这些都已经很好了,如果我通过单击完整图像并移动它来移动缩放区域,橙色框会相应地移动。

现在这是我的问题:我还希望能够通过将鼠标放在预览按钮上的橙色框内然后移动框来移动主缩放区域。我试图实现这一点的方式,我给预览按钮事件处理程序PreviewMouseDownPreviewMouseUp以及MouseMove这样的事件:

Button prevBut = new Button(); 
prevBut.PreviewMouseDown += PrevBut_PreviewMouseDown; 
prevBut.PreviewMouseUp += PrevBut_PreviewMouseUp; 
prevBut.MouseMove += PrevBut_MouseMove;

PreviewMouseDown检查鼠标位置是否真的在橙色框内。如果是,它记录开始位置并为按钮捕获鼠标。 PreviewMouseUp再次释放鼠标捕获。 MouseMove现在应该被调用并做一些事情来根据鼠标位置分别更新缩放从开始位置的变化。

private void PrevBut_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    MouseStartPosRelativeToPreviewButton = e.GetPosition((Button)sender);

    if ( [some calculation to verify that mouse position is within orange box] )
        ((Button)sender).CaptureMouse();
}


private void PrevBut_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    ((Button)sender).ReleaseMouseCapture();
}


private void PrevBut_MouseMove(object sender, MouseEventArgs e)
{
    if (((Button)sender).IsMouseCaptured)
    {
        Point PosRelativeToPreviewImage = e.MouseDevice.GetPosition((Button)sender);

        ..  [Do some calculations and update zoom plus the position of the orange box]
    }
}

问题是,PrevBut_MouseMove()当鼠标悬停在按钮上时会定期调用(我验证过),但是当按下鼠标按钮时调用 STOP。换句话说,如果我记录发生的事情,PrevBut_MouseMove()当我将鼠标移到按钮上方时,我会看到很多调用,然后当我单击按钮上的任意位置时,我会得到PrevBut_PreviewMouseDown(), 直接紧随其后PrevBut_PreviewMouseUp()(一旦我松开鼠标)。即使我按住鼠标按钮几秒钟,也不会记录一个动作。一旦我松开鼠标按钮,就会有更多PrevBut_MouseMove()的调用,直到鼠标离开按钮。正如我所说,我不明白这一点。为什么MouseMove鼠标按钮处于活动状态时不再触发?

顺便说一下,Adorner(橙色框)设置为IsHitTestVisible = false,所以据我了解,它不应该妨碍鼠标事件。(或者可以吗?)我已经花了很多时间试图找到一种解决方法,但无法让它发挥作用。将不胜感激你能给我的任何帮助。谢谢。

标签: c#wpfmousemove

解决方案


这是正常行为。该MouseMove事件仍由输入管理器引发。但是由于事件及其注册的处理程序是同步执行的(WPF 不实现异步事件),MouseMove处理程序只能在所有当前正在执行的处理程序(例如,MouseDown已返回)之后执行。这就是MouseDown中断MouseMove(在所有已注册事件处理程序的持续时间内)的原因。

如果您主要对鼠标按钮感兴趣MouseMove并且也想对鼠标按钮做出反应(当鼠标移动时),您应该在MouseMove. 您可以通过访问以下内容在事件
序列期间轮询按钮的状态来做到这一点:MouseMoveMouseEventArgs

// Track pressed mouse buttons to determine that the MouseButtonState.Released state
// immediately follows the MouseButtonState.Pressed button state
private bool IsMouseButtonPreviouslyPressed  { get; sete; }

private void OnMouseMove(object sender, MouseEventArgs e)
{
  Point currentMousePointerPosition = e.GetPosition(sender as IInputElement);
  var eventSource = sender as UIElement;

  if (e.LeftButton == MouseButtonState.Pressed)
  {
    IsMouseButtonPreviouslyPressed  = true;
    HandleLeftMouseButtonDown(currentMousePointerPosition, eventSource);
  }
  if (IsMouseButtonPreviouslyPressed  && e.LeftButton == MouseButtonState.Released)
  {
    IsMouseButtonPreviouslyPressed  = false;
    HandleLeftMouseButtonUp(currentMousePointerPosition, eventSource);
  }
  HandleMouseMove(currentMousePointerPosition, eventSource);
}

private void HandleLeftMouseButtonDown(Point mousePointerPosition, UIElement sourceElement)
{
    if ( [some calculation to verify that mouse position is within orange box] )
    {
      sourceElement.CaptureMouse();
    }
}

private void HandleLeftMouseButtonUp(Point mousePointerPosition, UIElement sourceElement)
{
    if ( [some calculation to verify that mouse position is within orange box] )
    {
      sourceElement.ReleaseMouseCapture();
    }
}

private void HandleMouseMove(Point mousePointerPosition, UIElement sourceElement)
{
    if (sourceElement.IsMouseCaptured)
    {
      ..  [Do some calculations and update zoom plus the position of the orange box]
    }
}

推荐阅读