control with "popup"

  • Thread starter Thread starter lukasz
  • Start date Start date
L

lukasz

It's fairly easy to make a control that, upon clicking it, displays a popup
panel with buttons on it. It's also easy to hide it if an user selects a
button within the panel. However, how to make it disappear if an user clicks
/outside/ the panel? I have tried overriding numerous messages, without
success. I guess an option would be to override the form's mouse click
event, but I don't find a good method. Btw, a combobox works like this --
only except a panel with buttons it drops a list.

lukasz
 
* "lukasz said:
It's fairly easy to make a control that, upon clicking it, displays a popup
panel with buttons on it. It's also easy to hide it if an user selects a
button within the panel. However, how to make it disappear if an user clicks
/outside/ the panel? I have tried overriding numerous messages, without
success. I guess an option would be to override the form's mouse click
event, but I don't find a good method. Btw, a combobox works like this --
only except a panel with buttons it drops a list.

<URL:http://vbaccelerator.com/article.asp?id=13309>
 
Thanks. The popup helper was not embedded inside the control so I moved
PopupWindowHelper to my control but I'm not certain of one thing: originally
the main form had:

protected override void OnHandleCreated(EventArgs e) {
popupHelper.AssignHandle(this.Handle);
}

which I substituted with the following in my control:

protected override void OnParentChanged(EventArgs e) {
popupHelper.AssignHandle(this.ParentForm.Handle);
base.OnParentChanged (e);
}

Is this a correct approach? Should I rather try to check for parent form's
OnHandleChanged?
 
Hi Lukasz,

the most reliable solution I've found for your problem is to set a Hook for
mouse messages and determine if the mouse was clicked outside of your
control.
Example:

class whatever:
{

//

// All the hook stuff is to determine if mouse was pressed outside of
control.

// If so, hide control.

//

#region hook

public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

//Declare hook handle as int.

static int hHook = 0;

//Declare mouse hook constant.

private const int WH_MOUSE = 7;

private const int WM_LBUTTONDOWN = 0x0201;

//Declare MouseHookProcedure as HookProc type.

HookProc MouseHookProcedure;

//Declare wrapper managed POINT class.

[StructLayout(LayoutKind.Sequential)]

private class POINT

{

public int x;

public int y;

}

//Declare wrapper managed MouseHookStruct class.

[StructLayout(LayoutKind.Sequential)]

private class MouseHookStruct

{

public POINT pt;

public int hwnd;

public int wHitTestCode;

public int dwExtraInfo;

}

//Import for SetWindowsHookEx function.

//Use this function to install thread-specific hook.

[DllImport("user32.dll",CharSet=CharSet.Auto,

CallingConvention=CallingConvention.StdCall)]

public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,

IntPtr hInstance, int threadId);

//Import for UnhookWindowsHookEx.

//Call this function to uninstall the hook.

[DllImport("user32.dll",CharSet=CharSet.Auto,

CallingConvention=CallingConvention.StdCall)]

public static extern bool UnhookWindowsHookEx(int idHook);


//Import for CallNextHookEx.

//Use this function to pass the hook information to next hook procedure in
chain.

[DllImport("user32.dll",CharSet=CharSet.Auto,

CallingConvention=CallingConvention.StdCall)]

public static extern int CallNextHookEx(int idHook, int nCode,

IntPtr wParam, IntPtr lParam);

public int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)

{

if(Visible && (wParam.ToInt32() == WM_LBUTTONDOWN) )

{

bool inside = true;

_IsMouseOutside = false;

//Marshall the data from callback.

MouseHookStruct MyMouseHookStruct = (MouseHookStruct)
Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

Point pt = PointToClient(new Point(MyMouseHookStruct.pt.x,
MyMouseHookStruct.pt.y));

Rectangle rect = new Rectangle(0,0, Width, Height);;

inside = rect.Contains(pt);



// do action depending on mouse position...

if(DDL.Visible)

inside |= DDL.Bounds.Contains(new Point(MyMouseHookStruct.pt.x,
MyMouseHookStruct.pt.y));

_IsMouseOutside = !inside;

if(_IsMouseOutside)Hide();

}



return CallNextHookEx(hHook, nCode, wParam, lParam);

}



#endregion



public whatever()

{

// do initialization here...



#region hook

// Create an instance of HookProc.

MouseHookProcedure = new HookProc(MouseHookProc);


hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure,
(IntPtr)0,AppDomain.GetCurrentThreadId());

//If SetWindowsHookEx fails.

if(hHook == 0 )

{

MessageBox.Show("SetWindowsHookEx Failed");

return;

}



#endregion hook

}

}

When disposing your control you should call UnhookWindowsHookEx.

Hope this helps.



Regards,

Munir Husseini (iCOMcept)
 
Back
Top