TiraULTI
TiraULTI

Reputation: 199

Windows form going behind after splash screen

I am working with Windows forms. I have set up a splash screen to appear when opening the program like this.

protected override void OnLoad(EventArgs e)
{
   base.OnLoad(e);
   this.FormBorderStyle = FormBorderStyle.None;
}

private void timer1_Tick(object sender, EventArgs e)
{
   progressBar1.Increment(15);
   if (progressBar1.Value == 30) timer1.Stop();
}

It has a progress bar and a timer. I got the idea from another post here. This is working OK, the splash screen is appearing as it should. On the windows form to appear after this I have:

Thread t = new Thread(new ThreadStart(splash));
t.Start();
Thread.Sleep(2000);

InitializeComponent();
t.Abort();

The problem is as follows. When I open the exe, the splash screens appear for about 2 secs as it should, and then when it goes away, the next form appears a second and then goes behind every other window I have opened.

Do you know how can I fix it?

Update 1:

public void splash()
{
   System.Windows.Forms.Application.Run(new Form2());
}

This is my splash screen

Final Update:

I got it to work this way.

        Splash splash = new Splash();
        Instalador instalador = new Instalador();

        splash.Show();
        Thread.Sleep(2 * 1000);
        splash.Close();

        Application.Run(instalador);

This on the main. I do not know how OK is this, but it works.

Upvotes: 2

Views: 2274

Answers (3)

Mursaleen Hassan
Mursaleen Hassan

Reputation: 59

After long time struggle i got the solution. Use the code into Login Form (Form_Load) this.Activate(); Example:

private void login_Load(object sender, EventArgs e)
{
     this.Activate();
}

Upvotes: 2

James Durda
James Durda

Reputation: 645

To answer your specific question, you might get away with just adding this.Activate() after InitializeComponent

Thread t = new Thread(new ThreadStart(splash));
t.Start();
Thread.Sleep(2000);

InitializeComponent();
this.Activate();
t.Abort();

However, at the very least, implement handshaking that shuts down the splash screen nicely rather than just aborting the thread.

Also, depending on exactly what you're doing in your splash screen thread, there may be a multitude of subtle issues - e.g. the Z-ordering issue you're currently having.

Typically, I launch my splash screens from Main() before Application.Run({main form}) and also call Application.Run({splashScreen}) from it's thread handler. Application.Run has thread affinity so the splash screen will get its own ApplicationContext which will properly hook Closing/Closed events to shutdown the thread and raise ThreadExit just by invoking or beginInvoking SplashScreen.Close() (typically from MainForm_Shown event handler). It also has other minor benefits such as Application.OpenForms containing the splash screen.

Taking this route has pretty much eliminated my bugs and frustrations with splash screens.

-Begin Edit-

A more thorough example:

Start up the second thread and ApplicationContext in Main()

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Thread t = new Thread(new ThreadStart(splash));
        t.IsBackground = true;
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        Application.Run(new Form1());
    }
    private static void splash()
    {
        Application.Run(new Form2());
    }
}

Splash screen with a SetProgress method added so you can update it externally if you wish.

public partial class Form2 : Form
{

    public Form2()
    {
        InitializeComponent();
        timer1.Start();
    }
    public void SetProgress()
    {
        if (this.InvokeRequired) //Should have been handled by SplashScreenHandler but check just in case.
            this.BeginInvoke(new Action(SetProgress));
        progressBar1.Increment(15);
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        progressBar1.Increment(15);
        if (progressBar1.Value == 30) timer1.Stop();
    }
}

Main form: Notice nothing in constructor and the Shown event handler shuts down the splash screen(s) without having to carry in a reference (if you're going to instead rely on the timer for status updates.)

public partial class Form1 : Form
{
    public Form1()
    {
        //Simulate a long init
        Thread.Sleep(2000);

        InitializeComponent();
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        foreach (var splashScreen in Application.OpenForms.OfType<Form2>())
        {
            splashScreen.BeginInvoke( (Action) delegate () { splashScreen.Close(); });
        }
    }
}

-End Edit-

Upvotes: 3

JohnSaps
JohnSaps

Reputation: 622

I had the same issue and after stuggling for a very long time I ended up doing the following in the Load event of the main form after closing the splash screen:

//Manually activate frmMain as it gets back in the Z-order by Windows when splash screen closes.
NativeMethods.SetForegroundWindow(this.Handle);
this.Activate();

Where "SetForegroundWindow" is defined as follows:

/// <summary>
/// Sets foreground window
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll")]
internal static extern bool SetForegroundWindow(IntPtr hWnd);

That being said we probably need to see more of your code.

Upvotes: 0

Related Questions