views:

229

answers:

2

EDIT 2

Okay, based on the advice on the answers below I eliminated my thread approach and now my program looks like this: program.cs

 static void Main(){

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

FrmWWCShell FrmWWCShell = null;
var splash = new FrmSplash();
splash.SplashFormInitialized += delegate
        {
         FrmWWCShell = new FrmWWCShell();
         splash.Close();
        };
Application.Run(splash);
Application.Run(FrmWWCShell);

}

And FrmSplash.cs like this:

public partial class FrmSplash : Form
{

    public FrmSplash()
    {
        InitializeComponent();
    }

    protected override void  OnLoad(EventArgs e)
    {
        splashTimer.Interval = 1;
        splashTimer.Tick +=
            delegate { if (SplashFormInitialized != null) SplashFormInitialized(this, EventArgs.Empty); };
        splashTimer.Enabled = true;
    }

    public event EventHandler SplashFormInitialized;
}

The problem is that it doesn't work at all now. The splash screen pops up for a split second, the marque progress bar never even initializes, and then disappears while I wait the 10 secs for the dll's and Main Form to show up while staring at nothing....

Color me severely confused now!


ORIGINAL POST--> for reference

I implemented a App Loading splash screen that operates on a seperate thread while all of the dll's are loading and the form is getting "Painted." That works as expected. What is strange is that now when the Splash form exits it sends my main Form to the back, if there is anything else open(i.e. Outlook). I start the thread in Program.cs,

static class Program
{
    public static Thread splashThread;

    [STAThread]
    static void Main()
    {
        splashThread = new Thread(doSplash);
        splashThread.Start();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmWWCShell());
    }

    private static void doSplash()
    {
        var splashForm = new FrmSplash();
        splashForm.ShowDialog();
    }
}

And then I end it once my FrmSearch_Shown event is fired.

private void FrmSearch_Shown(object sender, EventArgs e)
    {
        Program.splashThread.Abort();
        this.Show();
        this.BringToFront();
    }

I, as you can see, have tried calling a Show() and/or BringToFront() on FrmSearch and it still "jumps" to the back.

What am I missing?
What else can I try?
Am I doing this so horribly ignorant that it is my process that is causing this?
Should I file for early retirement?

Thanks for any insight!


EDIT 1

I tried setting the TopMost Property on my Main Form to TRUE. This keeps my form from hiding but it also keeps the user from looking at any other app. Seems a little narcissistic of me...

A: 

Try calling Application.DoEvents() right after show.

Warning: do not call DoEvents very often, but this is one of those time.

EDIT: Clyde noticed something I did not: you are threading this. Don't run any UI on another thread. Take out the thread, leave in the Application.DoEvents().

Chris Brandsma
Okay, I just tried that, same thing. Thanks for the time though!
Refracted Paladin
+3  A: 

First of all, it's very important that UI work is done on the primary application thread. I'm actually kind of surprised that you're not getting more serious errors already by showing the splash screen on a background thread.

Here's a technique I've used:

Use Application.Run on your splash form rather than your "real" form.

In your splash form, have an initialized event:

public event EventHandler SplashFormInitialized

Create a timer that fires in one millisecond, and triggers that event.

Then in your application run method you can load your real form, then close your splash form and do an Application.Run on the real form

var realForm = null;

var splash = new SplashForm();
splash.SplashFormInitialized += delegate {
  // As long as you use a system.windows.forms.Timer in the splash form, this
  // handler will be called on the UI thread
  realForm = new FrmWWCShell();
  //do any other init
  splash.Close();
}
Application.Run(splash); //will block until the splash form is closed

Application.Run(realForm);

The splash might include:

overrides OnLoad(...)
{
   /* Using a timer will let the splash screen load and display itself before
      calling this handler
   */
   timer.Interval = 1;
   timer.Tick += delegate {
     if (SplashFormInitialized != null) SplashFormInitialized(this, EventArgs.Empty);
   };
   timer.Enabled = true; 
}
Clyde
I might be thick but where would I put my version of the first part of your example? The var realForm=null --> Application.Run(realForm);Is that in Program.cs?Thanks!
Refracted Paladin
Yep, inside the Main() function.I'd caution you to use this as a guide rather than just copy and paste it and directly use it as production code. I was hoping to get across the idea that you need to show the splash screen on the UI thread, THEN after it's shown do your initialization. Then you can close the splash screen and open the real main form.
Clyde
No I didn't trully copy and paste but based on my issues I am obviously missing your point...sorry. Maybe "pretend" I have never used a delegate, threads, or a Splash screen before...
Refracted Paladin
OK, the delegates are probably the trickiest issue...What I'm going to do is edit the post above to give you an idea of the execution order. That might help
Clyde
oh wait, I read your update. Apparently you're needing to do more initialization before closing the splash form. The key is this code in the event handler:FrmWWCShell = new FrmWWCShell();splash.Close();I'm not sure what sort of initialization you're doing, but the idea is that everything that needs to be initialized needs to be done BEFORE you close the splash form.So maybe you need something like:FrmWWCShell = new FrmWWCShell();FrmWWCShell.Initialize();splash.Close();and then do your long-running stuff in the initialize
Clyde
Also, you mentioned a progress bar. That is on your splash screen, right?
Clyde
To explain a different way -- it sounds like the problem your having is that the long-running intialization isn't happening until after your main form is SHOWN. Your splash screen is appearing only for a split second because the 'new FrmWWCShell()' call is only taking a split second. If your using a splash screen, the idea is to get the startup code finished BEFORE showing the main form, not after.
Clyde
Yes, and the initialization is just all the dll's and then the load() of all the forms. Is is an Embedded form app with Tab Pages so it goes through and Paints the TabControls and Forms. I don't have any custom logic anywhere for the loading outside of that.Also, for FrmWWCShell.Initialize, that is another Delegate???
Refracted Paladin
Actually, no; I sit here and look and nothing for 10+ secs and then the Main Form comes up. If I watch the output window during that time a bunch of dll's are being loaded
Refracted Paladin
I was envisioning Initialize just as a simple method call.So this is an embedded app....that makes things more difficult.First, the easier part is the DLLs loading. For example if one of the dlls is the sqlce dll, then you could insert a line "SqlCeConnection c = new SqlCeConnection()". It doesn't do anything, but will force the DLL to load. Figure out which dlls are loading and in that event handler BEFORE closing the splash screen, write some dummy code like that which will force the dll to load.
Clyde
Hmm, not embedded as in for Mobile but embedded as in like this post here --> http://stackoverflow.com/questions/821094/embedded-form-in-a-control-or-form-as-user-control
Refracted Paladin