0

I'm using a loading screen in my winform application. So here I've

  1. main form (frmBilling)
  2. splashscreen form (frmsplash) and
  3. a class splashWorker.cs

This is the splashWorker.cs

public class splashWorker
    {
       public event EventHandler<splashWorkerEventArgs> ProgressChanged;
        public event EventHandler HardWorkDone;
        public void DoHardWork()
        {
            for (int i = 1; i <= 100; i++)
            {
                for (int j = 1; j <= 500000; j++)
                {
                    Math.Pow(i, j);
                }
                this.OnProgressChanged(i);
            }

            this.OnHardWorkDone();
        }

        private void OnProgressChanged(int progress)
        {
            var handler = this.ProgressChanged;
            if (handler != null)
            {
                handler(this, new splashWorkerEventArgs(progress));
            }
        }

        private void OnHardWorkDone()
        {
            var handler = this.HardWorkDone;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }
    public class splashWorkerEventArgs: EventArgs
    {
        public splashWorkerEventArgs(int progress)
        {
            this.Progress = progress;
        }

        public int Progress
        {
            get;
            private set;
        }
    }

and now, This is the code in splash screen.(There is a progressBar(progressBar1) in this form.)

 public partial class frm_splash : Form
  {
    private delegate void ProgressDelegate(int progress);

    private ProgressDelegate del;
    public frm_splash()
    {
        InitializeComponent();
        this.progressBar1.Maximum = 100;
        del = this.UpdateProgressInternal;
    }
    private void UpdateProgressInternal(int progress)
    {
        if (this.Handle == null)
        {
            return;
        }

        this.progressBar1.Value = progress;
    }
    public void UpdateProgress(int progress)
    {
        this.Invoke(del, progress);
    }
}

At last, this is the main form that I want to show after this splash screen loads.

public partial class frm_billingMain : Form
{
    private frm_splash splashScreen;
    private bool done = false;        

    public frm_billingMain(string get_uid)
    {
        InitializeComponent();
        this.Load += new EventHandler(HandleFormLoad);
        this.splashScreen = new frm_splash();
        c.uid = get_uid;
    }
    private void HandleFormLoad(object sender, EventArgs e)
    {
        this.Hide();

        Thread thread = new Thread(new ThreadStart(this.ShowSplashScreen));
        thread.Start();

        splashWorker worker = new splashWorker();
        worker.ProgressChanged += (o, ex) =>
        {
            this.splashScreen.UpdateProgress(ex.Progress);

        };

        worker.HardWorkDone += (o, ex) =>
        {
            done = true;
            this.Show();
        };

        worker.DoHardWork();
    }
    private void ShowSplashScreen()
    {
        splashScreen.Show();
        while (!done)
        {
            Application.DoEvents();
        }
        splashScreen.Close();
        this.splashScreen.Dispose();
    }

What is happens is , when I run the form , I'm getting an exception :

InvalidOperationException was unhandled.

"Cross-thread operation not valid: Control 'frm_splash' accessed from a thread other than the thread it was created on."

This error was showing in ShowSplashScreen() in frm_Billingmain

private void ShowSplashScreen()
        {
            splashScreen.Show(); **//The exception is pointing here**
            while (!done)
            {
                Application.DoEvents();
            }
            splashScreen.Close();
            this.splashScreen.Dispose();
        }

I tried a lot to solve and nothing happens well. Any help will be appreciated.

Thanks.

Athira Anu
  • 11
  • 3
  • 1
    Your `ProgressChanged` and `HardWorkDone` event handlers run on the worker thread, so can't directly access controls. Consider using a `BackgroundWorker` and its `ProgressChanged` and `RunWorkerCompleted` events instead. – Joe Nov 18 '15 at 07:28
  • You need to create a thread safe call. Like: `Invoke(new Action(() =>{ splashScreen.Show(); }));` – Shaharyar Nov 18 '15 at 07:34
  • Take a peek at the code in a question I recently asked. Though not perfect it might help in this case http://stackoverflow.com/questions/33570149/splash-screen-being-accessed-from-thread-it-was-not-created-on – KDecker Nov 18 '15 at 20:28

0 Answers0