鼠标事件发送者如何为null? (仅在Windows 8.1+触摸屏上)

时间:2018-08-09 06:20:41

标签: c# winforms event-handling touch mouseevent

这仅在Windows 8.1+触摸设备上发生。我有一些面板,用户可以在其中滑动手指。我已经实现了PreFilterMessage ,以便可以在整个应用程序中全局捕获鼠标的移动,而不必担心子控件的干扰。

在触摸设备上单击表单时,有时会收到一般错误:

IsCanceledMove() Object reference not set to an instance of an object.

我以空白表格进行测试,没有工具栏或工具条。只有两个面板。一个带有大标签,另一个带有按钮和文本框。这是我的鼠标移动过滤器,我将引发事件的发送方传递给引发异常的函数。

private static void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
{
     IsCanceledMove(sender as Control);
}

public bool PreFilterMessage(ref Message m)
{
      Point mousePosition = Control.MousePosition;
      var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);

      switch (m.Msg)
      {
          case WM_MOUSEMOVE:
              if (MouseFilterMove != null)
                     MouseFilterMove(Control.FromHandle(m.HWnd), args);
              break;

            // more cases
      }

        // Always allow message to continue to the next filter control
        return args.Handled;
}

接下来,我只是检查一下是否要移动的控件是文本框,以及该文本是否被突出显示。我还检查了另一个公共类的静态布尔变量。如果以上任何一个为真,则将LastTouchedPanel设置为null。 (类型为Panel

// On Mouse move check if text is behing high lighted
private static void IsCanceledMove(Control c)
{
     try
     {
          // If highlighting text, stop moving
          if (c.GetType() == typeof(TextBox))
              if ((c as TextBox).SelectionLength > 0)
                  LastTouchedPanel = null;

          // Checks a static boolean variable from another control class.
          if (UKSlider.IsSliding)
               LastTouchedPanel = null;
     }
     catch (Exception ex)
     {
          MessageBox.Show("IsCanceledMove() " + ex.Message);
     }
}

如果对象为空,该如何发送事件?如何为ARM设备处理该事件?在Windows 10的Vista上运行正常,但Windows 10 ARM则无法。

编辑:我注意到Control.FromHandle(m.HWnd)有时在我的PreMessageFilter和ARM设备上返回Null。放入空检查显然可以解决该异常,但是会错过一些移动事件。

1 个答案:

答案 0 :(得分:1)

空鼠标事件发送者与在触摸设备上使用IMessageFilter 直接相关。我已经在Windows 8.1触摸设备和Windows 10上看到了这种情况。

我在应用程序PreFilterMessage中的事件开始时开始。我想确保实际上Control.FromHandle创建了一个空的发件人。果然,我可以看到有时仅触摸表单上的开放空间将返回空控件。大概是无法转换为.NET Control类型的窗口句柄。

带有自定义控件的表单为空。我确定只能使用Control.FromHandle安全的控件。

因此,这引出了一个大问题-如何获取空引用以尝试转换这些控件?

由于我知道有问题的控件无法转换为.NET控件,因此我转向窗口句柄以查找一些信息。我注意在null控件上引发的窗口句柄。

当我单击表单中的空白区域时,可以看到我按预期获得了表单的窗口句柄。我注意到当我获得空引用时,该句柄不是来自应用程序中的任何控件。

我认为实际上只有一个答案,即手势控制器或类似的东西。这是我开始尝试一些手势的时候。在那里,数小时来我第一次很高兴看到空引用异常。

结果证明,用一根手指进行的移动会在表单中的PreMessageFilter中进行鼠标移动。用两个手指移动,您就可以从手势控制器获得鼠标移动 AND 作为表单的鼠标移动消息。无法将手势控制器强制转换为使用Control.FromHandle的控件。

这里发生的是我在测试期间变得懒惰,并且在单击时将手掌放在触摸屏上。

对于我的情况,我知道我只想处理鼠标移动,而不关心手势。我可以忽略空句柄。如果您想同时处理这两种情况,我认为您应该在PreMessageFilter中忽略它,并使用手势消息正确处理该手势。