Click here to Skip to main content
15,896,557 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm using a loading screen in my winform application. So here I've

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

This is the splashWorker.cs

C#
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.)

C#
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.

C#
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

C#
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.
Posted

1 solution

Well, it is exactky what is says:
Control 'frm_splash' accessed from a thread other than the thread it was created on

It was created on the UI thread in your frm_billingMain constructor:
C#
this.splashScreen = new frm_splash();
And you are using it in
ShowSplashScreen which is called in a separate thread:
C#
Thread thread = new Thread(new ThreadStart(this.ShowSplashScreen));
thread.Start();

You can't access controls from any thread other than the UI thread they were created on.
You could use Invoke to get round this, but in all honesty I'd dump most of that code as "not a good idea". Any time you end up using Application.DoEvents it normally means there is a real problem with your code, and to use it in a threaded environment means there is something seriously wrong.

I would start by looking at some of the many articles here on splash screens: Google splash screens on CodeProject[^] and see how they do it - you are over complicating things a lot! :laugh:
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900