We have a advanced software written by using c# ( windows forms ). In their we have 1000 or more textboxes. I need to validate user input on all these textboxes to stop entering
If you want to add the KeyDown
Event to all TextBoxes
you can loop through them and add the same EventHandler
for all of them.
To do that first of all we need to create a function that loop through all our TextBoxes.
GetChildControls Function:
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control)
where TControl : Control
{
var children = (control.Controls != null) ?
control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>();
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children);
}
We can now use that function after the InitializeComponent();
to assign the Txt_KeyDown()
EventHandler to all TextBoxes.
Calling the Function:
public Example() {
InitializeComponent();
var allTextBoxes = this.GetChildControls<TextBox>();
foreach (TextBox tb in allTextBoxes)
{
tb.KeyDown += Txt_KeyDown;
}
}
private void Txt_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
// Your code here
}
"Is there any way to handle this from a single place and affect for every textboxes"
There's a few ways. But it seems you don't want to edit the textbox itself, so there's only one reliable way I'm aware of; attaching a global keyboard hook. Code follows:
class GlobalKeyboardHook
{
#region DLL Imports
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int hookEventId, keyboardProc callback, IntPtr handleInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr handleInstance);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr ignoredParameter, int hookCode, int wParam, ref KeyboardHookStruct lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string libFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion DLL Imports
#region Class Declarations
private delegate int keyboardProc(int code, int wParam, ref KeyboardHookStruct lParam);
private keyboardProc kbdProc;
public struct KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int extraInfo;
}
private static class KeyboardMessages
{
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
}
IntPtr HookPointer = IntPtr.Zero;
IntPtr ModuleInstance = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion Class Declarations
#region Class Functions
public GlobalKeyboardHook() {
EnableHook(true, null);
}
public GlobalKeyboardHook(Process P) {
EnableHook(true, P);
}
~GlobalKeyboardHook() {
EnableHook(false, null);
}
public void EnableHook(bool Enabled)
{
EnableHook(Enabled, null);
}
public void EnableHook(bool Enabled, Process P) {
if (Enabled)
{
HookPointer = SetWindowsHookEx(KeyboardMessages.WH_KEYBOARD_LL, kbdProc = HookCallback, ModuleInstance = P == null ? LoadLibrary("User32") : GetModuleHandle(P.MainModule.ModuleName), 0);
}
else
{
UnhookWindowsHookEx(HookPointer);
HookPointer = IntPtr.Zero;
ModuleInstance = IntPtr.Zero;
kbdProc = null;
}
}
public int HookCallback(int code, int wParam, ref KeyboardHookStruct lParam) {
if (code >= 0) {
KeyEventArgs key = new KeyEventArgs((Keys)lParam.vkCode);
if ((wParam == KeyboardMessages.WM_KEYDOWN || wParam == KeyboardMessages.WM_SYSKEYDOWN) && (KeyDown != null)) {
KeyDown(this, key) ;
} else if ((wParam == KeyboardMessages.WM_KEYUP || wParam == KeyboardMessages.WM_SYSKEYUP) && (KeyUp != null)) {
KeyUp(this, key);
}
if (key.Handled)
return 1;
}
return CallNextHookEx(HookPointer, code, wParam, ref lParam);
}
#endregion Class Functions
}
To activate we add the following:
GlobalKeyboardHook ghk = new GlobalKeyboardHook(Process.GetCurrentProcess());
Type tbType = typeof(TextBox);
ghk.KeyDown += new KeyEventHandler(() => {
if (typeof(this.ActiveControl) == tbType)
RunValidation(this.ActiveControl.Text);
});
Once you have the boilerplate hook, adding validation becomes pretty simple. No loops means you're not wasting processor time iterating over a thousand text boxes.
Just remember this will apply to ALL controls of type TextBox within the current process. If you add a custom TextBox control or don't want to check all of them - that should be accounted for prior to calling RunValidation().