8

I have a windows forms app with a toolstrip that contains buttons. Frustratingly, I have to click twice on any button to get it to fire when the form isn't focused. The first click seems to activate the form, and then second click clicks the button (alternatively, I can click anywhere on the form and then click the button once). How can I fix this so that, even when the form is not activated, I can click directly on a button?

EDIT: I feel like this should be feasible, since it works in programs like SQL Server Profiler and Visual Studio (not that these use WinForms, but it would suggest that it's not an OS issue).

ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
  • Seems like a good idea. Waiting patiently for an answer –  Feb 28 '14 at 19:16
  • 1
    I think those are the best answers:https://stackoverflow.com/a/4967537/767664 and https://stackoverflow.com/a/1892990/767664 – Pedro77 Dec 14 '17 at 13:07

2 Answers2

2

Try something like this:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;

private const int WM_PARENTNOTIFY = 0x210;
private const int WM_LBUTTONDOWN = 0x201;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_PARENTNOTIFY)
    {
        if (m.WParam.ToInt32() == WM_LBUTTONDOWN && ActiveForm != this)
        {
            Point p = PointToClient(Cursor.Position);
            if (GetChildAtPoint(p) is ToolStrip)
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, (uint)p.X, (uint)p.Y, 0, 0);
        }
    }
    base.WndProc(ref m);
}

EDIT: Works for ToolStrip now.

Dmitry
  • 13,797
  • 6
  • 32
  • 48
  • I've updated my example. Now it works for `ToolStrip` and skips excessive clicks for other controls. – Dmitry Feb 28 '14 at 20:23
  • 1
    I found the similar [Rick Brewster's solution](https://blogs.msdn.microsoft.com/rickbrew/2006/01/09/how-to-enable-click-through-for-net-2-0-toolstrip-and-menustrip/) worked well, just ensure you set `myToolStrip.ClickThrough = true`. – SharpC May 10 '19 at 15:28
0

Here's an alternative way to do this. You could use the Form's Activated event, then check if the mouse is over a toolstrip button and if so, call PerformClick().

private void Form1_Activated(object sender, EventArgs e)
{
    for (int i = 0; i < toolStrip1.Items.Count; i++)
    {
        ToolStripItem c = toolStrip1.Items[i];
        if (new RectangleF(new Point(i * (c.Size.Width - 1) + this.Location.X + 18, this.Location.Y + 32), c.Size).Contains(MousePosition))
            c.PerformClick();
    }
}

(The 18 and 32 are the offsets of the toolstripcontainer from the form's location). There may be a way to actually calucate what the X and Y offsets should be, but this worked for me. HTH

davidsbro
  • 2,761
  • 4
  • 23
  • 33