tags:

views:

186

answers:

3

Whenever a Form is opened, the system automatically focuses one of the controls for you. As far as I can tell, the control that gets focus is the first enabled control in the tab order, as per Windows standard behavior.

The question is how to change this at run time without having to dynamically reshuffle the tab order. For instance, some forms might want to vary the initially-focused control based on program logic, to put focus in the most appropriate control. If you just focus some other control inside your OnLoad handler, the default logic executes anyway and re-focuses the default control.

If you're writing in C/C++ and using a raw window procedure or MFC, you can return 0 (FALSE) from your WM_INITDIALOG handler, and the default focusing logic gets skipped. However, I can't find any way to do this in Windows Forms. The best I've come up with is to use BeginInvoke to set the focus after the OnLoad finishes, like so:

protected override void OnLoad( System.EventArgs e )
{
    base.OnLoad( e );
    // ... code ...
    BeginInvoke( new MethodInvoker( () => this.someControl.Focus() ) );
}

There must be some proper way to do this - what is it?

+1  A: 
   public void ControlSetFocus( Control^ control )
   {

      // Set focus to the control, if it can receive focus.
      if ( control->CanFocus )
      {
         control->Focus();
      }
   }
Robert Harvey
Thanks - this generally works for focusing a control, but it doesn't help with the case I'm describing.
Charlie
Why?................
Robert Harvey
I agree with Adam. You need an event that occurs later in the form's startup cycle.
Robert Harvey
Right, that was the idea with the BeginInvoke method, it just doesn't seem very clean. The reason it doesn't work to just call Focus (if I understood your idea right) is that the system does its default focusing logic after OnLoad returns, so it doesn't matter what method I use to focus the control - the effect is lost. See also my comments to @Adam.
Charlie
Couldn't you set a flag when OnLoad fires, and clear it after you've performed your focus during OnActivate?
Robert Harvey
A: 

Instead of using the OnLoad event can't you use Form.Activated or Form.Shown events to see if they are called post rendering of control focus?

Adam Fox
Thanks for the ideas. I'm holding out for some other solution, though, because these events can occur multiple times in the lifetime of a form. Ideally I only want to change the focus when the form first opens - after that, whatever the user was doing should be preserved.
Charlie
Im not sure those events are called any more times than the Onload event, just when the form opens. Check here http://msdn2.microsoft.com/en-us/library/86faxx0d.aspx ... and you should be able to manage how many times your focus logic gets fired within the form itself
Adam Fox
Unfortunately, that graphic is somewhat misleading. 'Activated' will actually fire every time you switch back to your form after switching away to some other app/form. 'Shown' will fire each time you Show the form, which can happen more than once if you're using a modeless form and showing/hiding it (versus using ShowDialog to modally show the form).
Charlie
+5  A: 

After digging around through Reflector, I found what appears to be the "correct" way to do this: using ContainerControl.ActiveControl. This can be done from OnLoad (or elsewhere; see the docs for limitations) and directly tells the framework which control you want to be focused.

Example usage:

protected override void OnLoad( System.EventArgs e )
{
    base.OnLoad( e );
    // ... code ...
    this.ActiveControl = this.someControl;
}

This seems like the cleanest and simplest solution so far.

Charlie
Thanks. It works!
Peter Mortensen