2

My WinForms app has a simple modal login form, invoked at startup via ShowDialog(). When I run from inside Visual Studio, everything works fine. I can just type in my User ID, hit the Enter key, and get logged in.

But when I run a release build directly, everything looks normal (the login form is active, there's a blinking cursor in the User ID MaskedEditBox), but all keypresses are ignored until I click somewhere on the login form. Very annoying if you are used to doing everything from the keyboard.

I've tried to trace through the event handlers, and to set the focus directly with code, to no avail.

Any suggestions how to debug this (outside of Visual Studio), or failing that - a possible workaround?

Edit

Here's the calling code, in my Main Form:

    private void OfeMainForm_Shown(object sender, EventArgs e)
    {
        OperatorLogon();
    }

    private void OperatorLogon()
    {
        // Modal dialogs should be in a "using" block for proper disposal
        using (var logonForm = new C21CfrLogOnForm())
        {
            var dr = logonForm.ShowDialog(this);

            if (dr == DialogResult.OK)
                SaveOperatorId(logonForm.OperatorId);
            else
                Application.Exit();
        }
    }

Edit 2

Didn't think this was relevant, but I'm using Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase for it's splash screen and SingleInstanceController support.

I just commented out the splash screen code, and the problem has disappeared. So that's opened up a whole new line of inquiry...

Edit 3

Changed title to reflect better understanding of the problem

Tom Bushell
  • 5,865
  • 4
  • 45
  • 60

3 Answers3

1

UI focus/redraw/etc. issues usually are rather straightforward to debug by using remote-debugging. I.e. use a second PC (virtual is just enough) where your application runs.

See this MSDN article for details.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • Thanks for the suggestion - I'll set that up. But once I do, how should I proceed? Are there specific events you would look at first? I'm not using any of them, but I see Form has Activated, Enter, etc - should I create empty handlers and set breakpoints? – Tom Bushell Dec 22 '10 at 22:59
  • 1
    Yes, that's what I usually do; think about where it _could_ happen, write empty handlers, set breakpoints and then inspect the callstack when a breakpoint is being hit. – Uwe Keim Dec 23 '10 at 05:32
1

Run this in your form code behind. It will tell you which control has focus by giving you the type and name of the control. Run it in form_shown because its the last event in the form load process.

private void Form1_Shown(object sender, EventArgs e)
{
    Control control = FindFocusedControl(this);
    MessageBox.Show("The focused control " + control.Name + " is of type " + control.GetType());
}
public static Control FindFocusedControl(Control control)
{
    var container = control as ContainerControl;
    while (container != null)
    {
        control = container.ActiveControl;
        container = control as ContainerControl;
    }
    return control;
}

If the answer isn't obvious after that, tell us what you get.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • Thanks for the suggestion. However, result is "correct" for both the passing and failing test - "The focused control OperatorIdField is of type MaskedEditBox". One interesting difference, though. Displaying the diagnostic MessageBox "fixes" the problem - when I close the MessageBox, I can immediately type in my username. If I comment out the "MessageBox.Show..." line, the problem re-appears. Does that provide any more clues as to where the problem might be? – Tom Bushell Dec 22 '10 at 22:48
  • 1
    @Tom Well, I'd say the problem is the splash screen. It's not returning focus back to the main form. You can show us the implementation or try http://stackoverflow.com/questions/3884200/splash-screen-does-not-return-focus-to-main-form – P.Brian.Mackey Dec 23 '10 at 13:55
  • @Brian - thanks for the link, it led me to a workaround (see my answer) – Tom Bushell Dec 23 '10 at 19:42
1

I've found a hack...er...I mean...workaround, that fixes the problem. The solution was buried in one of the comments of this answer (thanks, P. Brian Mackey, for providing the link to the related question!)

The workaround is to minimize the main window while the splash screen is displayed, then set it's WindowState back to Normal before showing the login form.

In the code below, see the lines commented with "HACK".

public class SingleInstanceController : WindowsFormsApplicationBase
{
    public SingleInstanceController()
    {
        this.IsSingleInstance = true;
    }

    /// <summary>
    /// When overridden in a derived class, allows a designer to emit code that 
    /// initializes the splash screen.
    /// </summary>
    protected override void OnCreateSplashScreen()
    {
        this.SplashScreen = new SplashScreen();
    }

    /// <summary>
    /// When overridden in a derived class, allows a designer to emit code that configures 
    /// the splash screen and main form.
    /// </summary>
    protected override void OnCreateMainForm()
    {
        // SplashScreen will close after MainForm_Load completed
        this.MainForm = new OfeMainForm();

        // HACK - gets around problem with logon form not having focus on startup
        // See also OfeMainForm_Shown in OfeMainForm.cs
        this.MainForm.WindowState = FormWindowState.Minimized;
    }
}


public partial class OfeMainForm : Form
{
    // ...

    private void OfeMainForm_Shown(object sender, EventArgs e)
    {
        // HACK - gets around problem with logon form not having focus on startup
        // See also OnCreateMainForm in Program.cs
        this.WindowState = FormWindowState.Normal;

        OperatorLogon();
    }

    // ...

}

This is working for now, but I'm wondering if I should explicitly open the Logon form from the SingleInstanceController, rather than from my main form.

Community
  • 1
  • 1
Tom Bushell
  • 5,865
  • 4
  • 45
  • 60