Introduction
Ever have the problem that your controls, like a TextBox, ComboBox or DataGridView for example, don't seem to be receiving any keyboard commands like Ctrl+A, Ctrl+C or Ctrl+V? It happens to me too.
I was working on an MDI program containing several childforms with multiple tab or splitter panels to hold forms controls. During the initial phase, it didn't really bother me that much. First make the app work, then make it user friendly. But after some time, I had to figure out a solution.
Background
After some testing, I discovered what was happening. All the keystrokes were getting captured by the MdiForm owning all other childforms and their controls. Fine, so I take a look at the sender object. It’s the MdiForm! Getting the control I was actually using was a pain, but I figured it out.
The first thing I tried was looping through the sender.Controls collection and testing which had the ContainsFocus property set to true.
private void MdiForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
foreach (Control ctl in sender.Controls)
{
if (ctl.ContainsFocus)
{
}
}
}
}
All I got were ChildForms. They were the correct Forms but not the controls I was looking for. So I figured that I would do the same thing on the ChildForm.Controls collection.
foreach (Control ctl in sender.Controls)
{
if (ctl.ContainsFocus)
{
foreach (Control ctl2 in sender.Controls)
{
if (ctl2.ContainsFocus)
{
}
}
}
}
This time it wasn't a form, but yet again not the control I was looking for. This was just the control that holds the control, that holds the control that holds the controls I was looking for. And this was just for one child form. Most controls were 4, 5 or even more collections away.
I decided to take a more flexible approach and use a recursive function:
public static Control GetActiveControlOnSender(object sender)
{
if(sender is Control)
return GetActiveControl((Control) sender);
return null
}
internal static Control GetActiveControl(Control control)
{
if (!sender.ContainsFocus)
return null;
foreach (Control ctl in sender.Controls)
{
if (ctl.ContainsFocus)
{
if (ctl.Controls.Count == 0)
{
return ctl;
}
else
{
return GetActiveControl(ctl);
}
}
}
return control;
}
All I had to do now was call the function from the KeyDown event and pass the sender object. Then look at the object and decide what needs to happen.
private void MdiForm_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control)
{
Control control = Common.GetActiveControlOnSender(sender)
switch (e.KeyCode)
{
case Keys.A:
if (control is TextBox)
((TextBox)control).SelectAll();
break;
case Keys.X:
if (control is TextBox)
((TextBox)control).Cut();
break;
case Keys.V:
if (control is TextBox)
((TextBox)control).Paste();
break;
case Keys.C:
if (control is TextBox)
((TextBox)control).Copy();
break;
}
}
}
This can be modified to work for any user control.
History
- 2008-11-28: First version