Windows Application: Focus MDI Forms by right click

T

Ty

Hello all

I'm working on a C# Windows Application with a MDIContainer and Forms
(MDI childs). By default, left-clicking on a MDI form will set the
focus to it. What is the easiest way to achieve the same for right-
click?
Catching right-click only on the form doesn't help much since we are
using a lot of usercontrols and the form is not catching clicks on
those usercontrols.
Only solution i see right now is, subscribing the form to the
mouseclick event on all of its controls and then focus itself on
rightclick. But that seems kind of akward...

Thanks!
 
S

Stefan Hoffmann

hi Ty,
Only solution i see right now is, subscribing the form to the
mouseclick event on all of its controls and then focus itself on
rightclick. But that seems kind of akward...
Implement IMessageFilter for your MDI forms, something like this should
work:

using System;
using System.Windows.Forms;

namespace WindowsFormsMDIApplication
{
public partial class MDIChild : Form, IMessageFilter
{
public MDIChild()
{
InitializeComponent();
}

public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 516)
{
BringToFront();
}
return false;
}

private void MDIChild_Load(object sender, EventArgs e)
{
Application.AddMessageFilter(this);
}
}
}

But I'm not sure about the correct message (int)516 is WM_RBUTTONDOWN.


mfG
--> stefan <--
 
T

Ty

Hi Stefan

thanks for your suggestion! it brought me on the right track.

at the end, i couldn't do it like that because:
-every mdichild would receive application messages. not practicable to
handle since only one is the real one... and the real one doesn't even
know it has been clicked...
-it is neccesary to know the z-order of the forms because otherwise
it's impossible to figure out wich control to activate if many forms
are on top of eachother
-the z-order of the forms does not seem to be available in .net

i came up with a class that handles activating forms on right click.
i'll copy the code below, maybe it helps someone. no please nobody
tell me that activating forms on right-click is just some property :)
this thing just cost me several hours, but it was interesting
nonetheless.

greetz

ty



simply instanciate below class somewhere in or after mdiparent_load
new MdiRightClickActivate(mdiparent);

******
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;


public class MdiRightClickActivate : IMessageFilter
{
Form m_mdiParent;
MdiClient m_mdiClient;
Dictionary<int, Form> m_formList;

const long GW_CHILD = 5;
const long GW_HWNDNEXT = 2;
const long GW_HWNDPREV = 3;

[DllImport("user32")]
static extern int GetWindow(int hWnd, long wCmd);

public MdiRightClickActivate(Form mdiParent)
{
m_mdiParent = mdiParent;
GetMdiClient();
Application.AddMessageFilter(this);
}

Dictionary<int, Form> GetZOrder()
{
Dictionary<int, Form> zorder = new Dictionary<int, Form>
();
BuildFormList();

int nextHwnd = GetWindow((int)m_mdiClient.Handle,
GW_CHILD);
int z = 0;
while (nextHwnd > 0)
{
if (m_formList.ContainsKey(nextHwnd))
{
zorder.Add(z, m_formList[nextHwnd]);
z++;
}
nextHwnd = GetWindow(nextHwnd, GW_HWNDNEXT);
}

return zorder;
}

public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 516)
ActivateCursorForm(Cursor.Position);
return false;
}

void ActivateCursorForm(Point onLocation)
{
Point clientCursorPoint = m_mdiClient.PointToClient
(onLocation);

foreach (Form form in GetZOrder().Values)
{
if (clientCursorPoint.X >= form.Location.X
&& clientCursorPoint.X <= form.Location.X +
form.Width
&& clientCursorPoint.Y >= form.Location.Y
&& clientCursorPoint.Y <= form.Location.Y +
form.Height)
{
if (m_mdiParent.ActiveControl != form)
{
form.Activate();
break;
}
}
}
}

void GetMdiClient()
{
m_mdiClient = null;

foreach (Control control in m_mdiParent.Controls)
{
if (control is MdiClient)
{
m_mdiClient = (MdiClient)control;
break;
}
}
}

void BuildFormList()
{
m_formList = new Dictionary<int, Form>();
foreach (Form form in m_mdiParent.MdiChildren)
{
m_formList.Add((int)form.Handle, form);
}
}
}

*******
 
T

Ty

here's a somewhat better version, checking first if clicked form is
already active.

simply instanciate below class somewhere in or after mdiparent_load
new MdiRightClickActivate(mdiparent);

******
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

public class MdiRightClickActivate : IMessageFilter
{
Form m_mdiParent;
MdiClient m_mdiClient;
Dictionary<int, Form> m_formList;

const long GW_CHILD = 5;
const long GW_HWNDNEXT = 2;
const long GW_HWNDPREV = 3;

[DllImport("user32")]
static extern int GetWindow(int hWnd, long wCmd);

public MdiRightClickActivate(Form mdiParent)
{
m_mdiParent = mdiParent;
GetMdiClient();
Application.AddMessageFilter(this);
}

Dictionary<int, Form> GetZOrder()
{
Dictionary<int, Form> zorder = new Dictionary<int, Form>
();
BuildFormList();

int nextHwnd = GetWindow((int)m_mdiClient.Handle,
GW_CHILD);
int z = 0;
while (nextHwnd > 0)
{
if (m_formList.ContainsKey(nextHwnd))
{
zorder.Add(z, m_formList[nextHwnd]);
z++;
}
nextHwnd = GetWindow(nextHwnd, GW_HWNDNEXT);
}

return zorder;
}

public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 516)
ActivateCursorForm(Cursor.Position);
return false;
}

void ActivateCursorForm(Point onLocation)
{
Point clientCursorPoint = m_mdiClient.PointToClient
(onLocation);

Form activeForm = (Form) m_mdiParent.ActiveControl;
if (PointIsInForm(activeForm, clientCursorPoint))
return;

foreach (Form form in GetZOrder().Values)
{
if (PointIsInForm(form, clientCursorPoint))
{
form.Activate();
break;
}
}
}

bool PointIsInForm(Form form, Point point)
{
return point.X >= form.Location.X
&& point.X <= form.Location.X + form.Width
&& point.Y >= form.Location.Y
&& point.Y <= form.Location.Y + form.Height;
}

void GetMdiClient()
{
m_mdiClient = null;

foreach (Control control in m_mdiParent.Controls)
{
if (control is MdiClient)
{
m_mdiClient = (MdiClient)control;
break;
}
}
}

void BuildFormList()
{
m_formList = new Dictionary<int, Form>();
foreach (Form form in m_mdiParent.MdiChildren)
m_formList.Add((int)form.Handle, form);
}
}
*****
 
S

Stefan Hoffmann

hi Ty,
simply instanciate below class somewhere in or after mdiparent_load
new MdiRightClickActivate(mdiparent);
Nice piece of work.



mfG
--> stefan <--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top