1

My Solution:

So I managed to find another tutorial http://www.codeproject.com/KB/dotnet/Yet_Another_Splash_Screen.aspx and the sourcecode seemed to make more sense to me. Here is the code i'm using now. Main() is left untouched.

Splash.cs

`

public partial class Frm_Splash : Form { delegate void ProgressDelegate(int percent); delegate void SplashShowCloseDelegate();

    /// <summary>
    /// To ensure splash screen is closed using the API and not by keyboard or any other things
    /// </summary>
    bool CloseSplashScreenFlag = false;

    /// <summary>
    /// Base constructor
    /// </summary>
    /// 
    public Frm_Splash()
    {
        InitializeComponent();
        progress_Splash.Show();
        this.ClientSize = this.BackgroundImage.Size;
    }

    public void ShowSplashScreen()
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new SplashShowCloseDelegate(ShowSplashScreen));
            return;
        }
        this.Show();
        Application.Run(this);
    }

    /// <summary>
    /// Closes the SplashScreen
    /// </summary>
    public void CloseSplashScreen()
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new SplashShowCloseDelegate(CloseSplashScreen));
            return;
        }
        CloseSplashScreenFlag = true;
        this.Close();
    }

    /// <summary>
    /// Update text in default green color of success message
    /// </summary>
    /// <param name="Text">Message</param>
    public void Progress(int percent)
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new ProgressDelegate(Progress), new object[] { percent });
            return;
        }
        // Must be on the UI thread if we've got this far
        progress_Splash.Value = percent;
        // Fade in the splash screen - looks pro. :D
       if (percent < 10)
            this.Opacity = this.Opacity + .15;
    }


    /// <summary>
    /// Prevents the closing of form other than by calling the CloseSplashScreen function
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SplashForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (CloseSplashScreenFlag == false)
            e.Cancel = true;
    }
 }`

Form1.cs

public partial class Frm_Main : Form
{
    Frm_Splash frm_Splash = new Frm_Splash();

    public Frm_Main()
    {
        this.Hide();
        Thread splashthread = new Thread(new ThreadStart(frm_Splash.ShowSplashScreen));
        splashthread.IsBackground = true;
        splashthread.Start();
        InitializeComponent();
        CenterToScreen();
    }

    private void Frm_Main_Load(object sender, EventArgs e)
    {
        if (PassedAll() == true)
            FillMovieLB();
        if (FillMovieProgress == 100)
        {
            //Throw in this sleep so the user can see the progress bar reach all the way to the end.
            Thread.Sleep(1000);
            this.Show();
            frm_Splash.CloseSplashScreen();
            this.Activate();
        }
    }

Original Question

G'day all,

I'm very new to programming in C# and i'm having a problem with the http://www.codeproject.com/KB/cs/prettygoodsplashscreen.aspx tutorial and implementing it within my application. I'm finding it a little difficult to understand what the problem is. I know there is alot of stuff about getting this splash screen to work but I can't get my head around it.

When I start the program, the Frm_Main will display, you can see the listbox being populated, because i've placed it in BackgroundWorker.DoWork(), and then afterwards my frm_Splash will show after the work is done. Obviously, the way it should be working is, frm_Splash will show during the work being done on Frm_Main, and the progress bar will show the progress of the loading (this part I haven't implemented yet).

Edit: I may not have been clear, but the question is: How can I get my splashscreen to display while the work is being done and before the main form is displayed?

Thanks everybody. :)

Here is my code:

   static Frm_Splash frm_Splash = new Frm_Splash();

    public delegate void ShowFormDelegate();

    public void ShowForm()
    {
        frm_Splash.Show();
    }

    public Frm_Main()
    {
        InitializeComponent();
        CenterToScreen();
        if (PassedAll() == true)
        {
            back_loadprog.RunWorkerAsync();  
        }
    }

   private void back_loadprog_DoWork(object sender, DoWorkEventArgs e)
    {
        Invoke(new ShowFormDelegate(ShowForm));
        Invoke(new FillMovieLBDelegate(FillMovieLB));
    }
Matty_R
  • 25
  • 1
  • 8

2 Answers2

3

Here, have some code... Works for me.

Splash Form:

namespace Screens.Forms
{
    public partial class Splash : DevExpress.XtraEditors.XtraForm
    {
        public Splash()
        {
            InitializeComponent();
        }
        string RandomLoadingMessage()
        {
            string[] lines ={
                "Pripremam warp pogon",
                "Moj drugi ekran za učitavanje je brži, probaj njega",
                "Verzija programa koju imam u testiranju imala je smiješnije poruke"
            };
            return lines[new Random().Next(lines.Length)];
        }
        public void RandomizeText()
        {
            lblMessage.Text = RandomLoadingMessage();
        }
        private void Splash_Load(object sender, EventArgs e)
        {
            RandomizeText();
        }
        private static Splash _splash;
        private static bool _shouldClose;

        static void ThreadFunc()
        {
            _splash = new Splash();
            _splash.Show();
            while (!_shouldClose)
            {
                Application.DoEvents();
                Thread.Sleep(100);
                if (new Random().Next(1000) < 10)
                {
                    _splash.Invoke(new MethodInvoker(_splash.RandomizeText));
                }
            }
            for (int n = 0; n < 18; n++)
            {
                Application.DoEvents();
                Thread.Sleep(60);
            }
            if (_splash != null)
            {
                _splash.Close();
                _splash = null;
            }
        }
        static public void ShowSplash()
        {
            _shouldClose = false;
            Thread t = new Thread(ThreadFunc);
            t.Priority = ThreadPriority.Lowest;
            t.Start();
        }
        internal static void RemoveSplash()
        {
            _shouldClose = true;
        }
        internal static void ShowSplash(List<string> fromTwitterMessages)
        {
            ShowSplash();
        }
    }
}

Show it with:

Splash.ShowSplash();

Do the work you need, then when done:

Splash.RemoveSplash();
Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
  • Thanks for the code. I'll see what I can do with it. I think the biggest difference i'm seeing is that i'm adding a WinForm onto my existing project, whereas alot of examples have the SplashScreen form as the main project and then just loading another screen afterwards that has all the controls. – Matty_R Jul 14 '11 at 12:08
  • I am showing splash from the Program.CS before firing up the main form, and then am closing it when main form has completed OnLoad event. That way everything works exactly as needed, and splash is even on top and main form is loading in the background visually. This method I use creates another message loop for that form that is completely isolated from the main msg loop. – Daniel Mošmondor Jul 14 '11 at 12:42
  • 1
    Used this in 2022 – MX313 Jun 22 '22 at 20:07
1

You need to take this a step further back to your Main() function of the application. In general you could do this:

  • Create a ManualResetEvent or better ManualResetEventSlim if you are on .NET 4
  • Start a new thread displaying your SplashScreen, use Application.Run
  • In your SplashScreen you should create a time which polls the created ManualResetEvent frequently, a nice animation could be placed here also
  • If the event is set you should close the form
  • Back in your Main() do your stuff like creating forms etc.
  • When finish set the event, so that the SplashScreen can be closed
  • To be sure that your MainForm is not shown before your SplashScreen is closed you can use another event
ba__friend
  • 5,783
  • 2
  • 27
  • 20
  • I understand some of what you're getting at. The `Invoke(new ShowFormDelegate(ShowForm));` is supposed to starting another thread, but if I use `Application.Run` inside ShowForm() it creates an exception. "Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead." – Matty_R Jul 14 '11 at 12:04
  • As I posted, you have to do it before you call `Application.Run()` with your `MainForm`. In the `Main()` function of your Application. – ba__friend Jul 14 '11 at 12:06
  • 1
    Gotcha, wasn't sure what the `Main()` function you mentioned was actually referring to. I've made some progress since changing that now. Cheers. – Matty_R Jul 14 '11 at 12:20