Windows Form Application - Splash screen label not updating

921 views Asked by At

I have a windows form application which is supposed to show a splash screen with a label field that I want to update as the main form (called welcome.cs) loads in the background. The splash screen shows & hides just fine, but the label doesn't update.

I've done a lot of research but haven't quite found the solution.

Program.cs

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

            SplashScreen splashscreen = new SplashScreen();
            splashscreen.ShowSplashScreen();

            Welcome welcome = new Welcome(splashscreen); //Takes some time to load
            splashscreen.CloseForm();
            Application.Run(welcome);

        }
    }

Splashscreen.cs

public partial class SplashScreen : Form
    {
        //Delegate for cross thread call to close
        private delegate void CloseDelegate();
        private delegate void UpdateStatusDelegate(string status);
        private static SplashScreen splashScreen;
        private Thread thread = null;

        public SplashScreen()
        {
            InitializeComponent();
        }

        public void ShowSplashScreen()
        {
            // Make sure it is only launched once.

            if (splashScreen != null)
                return;
            thread = new Thread(ShowForm);
            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

        static private void ShowForm()
        {
            splashScreen = new SplashScreen();
            Application.Run(splashScreen);
        }

        public void CloseForm()
        {
            splashScreen.Invoke(new CloseDelegate(CloseFormInternal));
        }

        static private void CloseFormInternal()
        {
            splashScreen.Close();
        }

        public void UpdateStatus(string status)
        {
            splashScreen.Invoke(new UpdateStatusDelegate(UpdateStatusInternal), status);
        }

         private void UpdateStatusInternal (string status)
        {
             if (splashScreen != null && splashScreen.IsHandleCreated)
             {
                 lblStatus.Text = status;
             }

        }
    }

Welcome.cs

public Welcome(Splashscreen splashscreen)
{
        InitializeComponent();
        //Code to log the user into the system

        splashScreen.UpdateStatus("Logging in...");
        //my expectation is that UpdateStatus call will update the label displayed on the splash screen but it doesn't.

        //Do more stuff.....
}

Does it have something to do with multi-threading or is it because im creating a new instance of splashscreen in welcome.cs before calling UpdateStatus? How would I get around this?

1

There are 1 answers

0
Ewerton On

You could do the following

 static void Main()
 {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);

     string[] args = Environment.GetCommandLineArgs();

     // Creates the Splash
     splash = new FrmSplash();

     //Opens the Splash in a new Thread, this way any gifs, progress bars, lablels changes will work because the main thread isnt blocked
     var t = Task.Factory.StartNew(() =>
     {
         splash.ShowDialog();
     });

      while (!splash.Created) // wait the splash screen form load process
          System.Threading.Thread.Sleep(300);

     UpdateSplashMessage("Loading the program... Please wait");         
     // Some slow initialization code.
     // ...

     //Close splash screen
     CloseSplash();

     Application.Run(args);
 }

 static void CloseSplash()
 {
     splash.Invoke(new MethodInvoker(() =>
     {
         splash.Close(); // Closes the splash that is running in the other thread
     }));
 }

 static void UpdateSplashMessage(string msg)
 {
     splash.Invoke(new MethodInvoker(() =>
     {
         splash.AtualizarMensagem(msg);
     }));
 }

Note that you will need to create a method called AtualizarMensagem(string str) in your splash screen form, like this

public void AtualizarMensagem(string novaMsg)
{
    lblCarregando.Text = novaMsg;
}

I have this code in my "useful snnipets" folder, it always works for me. Hope this helps.