0

So I understand that you are only allowed to access a UI control from the thread it was created on, but I am getting an error complaining about the line 'this.Close()'. What I am trying to do is start a thread that opens a splash screen with an OpenTK animation.

ERROR: "The calling Thread cannot access this object because a different thread owns it."

Here is the code:

  public MainWindow()
    {

        InitializeComponent();

          closeSplashBool = false;              

          Thread t = new Thread(() =>
              {
                  openSplash = new SplashScreen();
                  openSplash.Show();

              }
                  );
          t.SetApartmentState(ApartmentState.STA);
          t.Start(); 

    ///
    /// Long running task
    ///

    closeSplashBool = true;
    }

The only line of code in the constructor for SplashScreen is InitializeComponents(). Here is my animation function for the SplashScreen class (which controls when the splash screen is closed):

        private void splashControl_Paint(object sender, PaintEventArgs e)
    {
        //make sure our GL control has loaded
        if (!loaded)
            return;



        if (animCount <= 0 )
        {
            Thread.Sleep(200);
            if (MainWindow.closeSplash)
                this.Close();  //program crashes on this line
        }
        else if (animCount < 3.75 && animCount >=2.75)
        {
            animCount -= .2f;
            System.Threading.Thread.Sleep(1);
        }
        else if (animCount < 2.75)
        {
            animCount -= .07f;
            System.Threading.Thread.Sleep(5);
        }
        else 
        {
            animCount -= .7f;
            System.Threading.Thread.Sleep(1);
            if (animCount < 0)
                animCount = 0;
        }
        Render();
    }

I made a 'new' Splash Screen in Thread 't', so I figured calling 'this.Close()' would not have any access violations. My question is why am I getting this access violation? I have tried replacing 'this.close' with 'Dispatcher.InvokeShutdown' on suggestions from others, but then the Splash Screen never went away.

TheBlindSpring
  • 631
  • 5
  • 22
  • 1
    Is there a reason why your not using the built in WPF framework for showing a splash screen by simply adding a 'New Item' -> 'SplashScreen (WPF)' to your VS project? – AwkwardCoder Jul 17 '14 at 20:22
  • 1
    Don't create multiple UI threads. You're just asking for trouble. Rather than creating a second UI thread to show a UI while you do non-UI work in your first UI thread, just show your form in your one and only UI thread and do your non-UI work in a non-UI thread. – Servy Jul 17 '14 at 20:23
  • @AwkwardCoder I have never used (or heard of) 'New Item' -> 'SplashScreen (WPF)'. How is this different from making a new window? Servy That is my last resort at this point, but I have thought of that and you are right that should work. – TheBlindSpring Jul 17 '14 at 20:29
  • It's the simplest solution for a splash screen, so why not use it? – AwkwardCoder Jul 17 '14 at 20:43
  • 1
    You could create the splash screen on the UI thread and create a timer that fires after your desired delay. The timer's event handler would then call the `Close` method on the splash screen. – Jim Mischel Jul 17 '14 at 20:46
  • @AwkwardCoder I can't find the 'Splash Screen (WPF)' in add new items. I am using VS Express 2013. – TheBlindSpring Jul 17 '14 at 21:15
  • this is an alternative way to do it http://msdn.microsoft.com/en-us/library/cc656886(v=vs.110).aspx – AwkwardCoder Jul 17 '14 at 21:25

1 Answers1

-1

see the MSDN MethodInvoker Delegate (System.Windows.Forms)

    private void splashControl_Paint(object sender, PaintEventArgs e)
    {
        // see the http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28SYSTEM.WINDOWS.FORMS.METHODINVOKER%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22%29;k%28DevLang-CSHARP%29&rd=true
        if (!this.IsHandleCreated && !this.IsDisposed) return;

        if (this.InvokeRequired)
        {
            this.Invoke(new MethodInvoker(() => { splashControl_Paint(sender, e); }));
        }
        else
        {
            // place splashControl_Paint CODE HERE
        }
    }
khan
  • 4,479
  • 1
  • 15
  • 9