【问题标题】:Trigger button click in .NET Compact Framework在 .NET Compact Framework 中触发按钮单击
【发布时间】:2015-05-19 15:03:34
【问题描述】:

假设我有一个包含许多 Button 和 PictureBox 控件的面板。每个控件都有一个关联的 Click 事件。这是一个触摸屏应用程序,因此用户的点击可能有点不精确(或者触摸屏校准可能不完美)。所以,我想处理面板上的点击事件,然后如果点击靠近按钮/图片,则以编程方式调用按钮或图片框的点击事件。

许多其他答案建议使用“PerformClick”事件,但 Compact Framework 不支持此操作。有什么选择吗?我的代码:

private void pnlButtons_Click(object sender, EventArgs e)
{
    Point ptClick = Control.MousePosition;
    foreach (Control cntrl in pnlButtons.Controls)
    {
        // Make sure the control is visible!
        if (cntrl.Visible)
        {
            // Click close to control?
            if ((ptClick.X > (cntrl.Left - 5)) &&
                (ptClick.X < (cntrl.Right + 5)) &&
                (ptClick.Y > (cntrl.Top - 5)) &&
                (ptClick.Y < (cntrl.Bottom + 5)))
            {
                // Click Button or PictureBox without cntrl.PerformClick?
            }
        }
    }
}

【问题讨论】:

  • 为什么要执行点击事件而不是点击事件调用的函数呢?所以:点击事件 CE1 调用函数 A,它调用函数 B、C、D 和 E。而不是调用 CE1,你可以只调用 A。
  • 是的,好主意,但面板上的每个控件的功能略有不同。所以按钮 A => A_click 调用 FunctionA(),按钮 B => B_click 调用 FunctionB(),PictureBox C => C_click 调用 FunctionC() 等等,以获取大量按钮和图片。
  • 很抱歉,我没有时间或东西来完整地写出答案,但我相信这并不难。首先,尝试子类化按钮并从您自己的 PerformClick 中调用 click 事件。否则,您可以编写一个获取按钮并执行单击的方法。首先获取控件的句柄,然后 p/调用 Windows API 函数以向其发送 mousedown 然后 mouseup 事件。我相信它是 SendMessage 功能。然后,您所要做的就是编写逻辑以找到最近的按钮并将其传递给函数。或者,将其写为 Button 的扩展方法...
  • @Alan:好主意,谢谢。我刚刚 P/Invoked SendMessage 并向控件发送了 WM_LBUTTONDOWN 和 WM_LBUTTONUP 消息,它按预期工作。如果您快速回答,我可以接受。否则,我明天会按照这些思路回答。
  • @AlainD 不客气,作为答案发布,随时编辑并复制 DllImports 的意大利面以供未来用户使用。

标签: c# .net compact-framework


【解决方案1】:

由于您不能使用PerformClick,因此在这种情况下您将无法依赖控件的Click 事件处理程序自动触发。取而代之的是,只需创建一个获取控件的方法并从该控件中找出要执行的操作。示例:

private void pnlButtons_Click(object sender, EventArgs e)
{
    Point ptClick = Control.MousePosition;
    foreach (Control cntrl in pnlButtons.Controls)
    {
        // Make sure the control is visible!
        if (cntrl.Visible)
        {
            // Click close to control?
            if ((ptClick.X > (cntrl.Left - 5)) &&
                (ptClick.X < (cntrl.Right + 5)) &&
                (ptClick.Y > (cntrl.Top - 5)) &&
                (ptClick.Y < (cntrl.Bottom + 5)))
            {
                handleClick (cntrl);
            }
        }
    }
}

private void handleClick(Control c)
{
    if (c == button1)
    {
        // handle button1 click, e.g. by calling its `Click` handler
    }
    else if (c == picureBox1)
    {
        // handle pictureBox1 click
    }
    // et cetera
}

【讨论】:

    【解决方案2】:

    首先,尝试子类化按钮并从您自己的 PerformClick 中调用 click 事件。否则,您可以编写一个获取按钮并执行单击的方法。首先获取控件的句柄,然后 p/调用 Windows API 函数以向其发送 mousedown 然后 mouseup 事件。我相信它是 SendMessage 功能。然后,您所要做的就是编写逻辑以找到最近的按钮并将其传递给函数。或者,将其写为 Button 的扩展方法

    https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx

    编辑: 下面是通过向控件发送 mousedown 和 mouseup 消息来模拟点击的完整代码:

    // Windows constants for mouse messages
    private const int WM_LBUTTONDOWN        = 0x0201;
    private const int WM_LBUTTONUP          = 0x0202;
    
    // P/Invoke for SendMessage
    [DllImport("coredll.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int nMsg, IntPtr wParam, IntPtr lParam);
    
    // Method to click a control
    public void ClickControl(IntPtr hWnd)
    {
        // Send a MOUSE_DOWN and MOUSE_UP message to the control to simulate a click
        SendMessage(hWnd, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
        SendMessage(hWnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
    }
    
    // Method to handle click event on parent Panel control
    private void pnlButtons_Click(object sender, EventArgs e)
    {
        // See if the click point is close to a (visible) button and if so, click the button.
        // The user was probably a little imprecise or the screen might need re-calibration.
        Point pt = pnlButtons.PointToClient(Cursor.Position);
    
        // Now look for any Button / PictureBox controls nearby
        foreach (Control cntrl in pnlButtons.Controls)
        {
            Rectangle inflated = cntrl.Bounds;
            inflated.Inflate(4, 5);
            if (cntrl.Visible && inflated.Contains(pt))
            {
                // Simulate a click on the control
                ClickControl(cntrl.Handle);
                break;
            }
        }
    }
    

    【讨论】:

    • @AlainD 看起来不错。我帮助简化了代码。
    • @AlainD 我删除了一个 LINQ 表达式,即使在旧版本的 CF 中也应该没问题
    • @AlainD Np,我更正了,对不起,我没有启动 IDE 和新项目只是为了写出示例。我的意思是“足够接近”并不重要“任何人都可以做对。它没有使用全新的 .NET 4.5 或 5.0 功能.. =)
    • OK,编辑批准,这结合了您的代码改进并在 CF 中编译!其他 cmets 已删除(您可能也想删除您的 cmets)。再次感谢。
    【解决方案3】:

    将按钮单击处理程序中的所有内容放到一个单独的函数中,并调用该函数而不是触发按钮单击。

    private void pnlButtons_Click(object sender, EventArgs e)
    {
        Point ptClick = Control.MousePosition;
        foreach (Control cntrl in pnlButtons.Controls)
        {
            // Make sure the control is visible!
            if (cntrl.Visible)
            {
                // Click close to control?
                if ((ptClick.X > (cntrl.Left - 5)) &&
                    (ptClick.X < (cntrl.Right + 5)) &&
                    (ptClick.Y > (cntrl.Top - 5)) &&
                    (ptClick.Y < (cntrl.Bottom + 5)))
                {
                    PerformActionsOnClick();
                }
            }
        }
    }
    private void MyButton_Click(object sender, EventArgs e)
    {
        PerformActionsOnClick();
    }
    void PerformActionsOnClick()
    {
        //do your stuff here
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多