Многопоточность не может получить доступ к this.close()

Итак, я понимаю, что вам разрешен доступ к элементу управления пользовательского интерфейса только из потока, в котором он был создан, но я получаю сообщение об ошибке, жалующееся на строку «this.Close()». Я пытаюсь запустить поток, который открывает заставку с анимацией OpenTK.

ОШИБКА: «Вызывающий поток не может получить доступ к этому объекту, поскольку им владеет другой поток».

Вот код:

  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;
    }

Единственная строка кода в конструкторе SplashScreen — InitializeComponents(). Вот моя функция анимации для класса SplashScreen (который управляет закрытием экрана-заставки):

        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();
    }

Я сделал «новый» экран-заставку в потоке «t», поэтому я решил, что вызов «this.Close()» не будет иметь никаких нарушений прав доступа. Мой вопрос: почему я получаю это нарушение прав доступа? Я попытался заменить «this.close» на «Dispatcher.InvokeShutdown» по предложениям других, но заставка так и не исчезла.


person TheBlindSpring    schedule 17.07.2014    source источник
comment
Есть ли причина, по которой вы не используете встроенную структуру WPF для отображения заставки, просто добавив «Новый элемент» -> «SplashScreen (WPF)» в свой проект VS?   -  person AwkwardCoder    schedule 18.07.2014
comment
Не создавайте несколько потоков пользовательского интерфейса. Вы просто напрашиваетесь на неприятности. Вместо того, чтобы создавать второй поток пользовательского интерфейса для отображения пользовательского интерфейса, пока вы выполняете работу, не связанную с пользовательским интерфейсом, в своем первом потоке пользовательского интерфейса, просто покажите свою форму в своем единственном потоке пользовательского интерфейса и выполняйте свою работу, не связанную с пользовательским интерфейсом, в потоке, отличном от пользовательского интерфейса.   -  person Servy    schedule 18.07.2014
comment
@AwkwardCoder Я никогда не использовал (и не слышал) «Новый элемент» -> «Заставка (WPF)». Чем это отличается от создания нового окна? Servy Это мое последнее средство на данный момент, но я думал об этом, и вы правы, это должно сработать.   -  person TheBlindSpring    schedule 18.07.2014
comment
Это самое простое решение для экрана-заставки, так почему бы им не воспользоваться?   -  person AwkwardCoder    schedule 18.07.2014
comment
Вы можете создать заставку в потоке пользовательского интерфейса и создать таймер, который срабатывает после желаемой задержки. Затем обработчик событий таймера вызовет метод Close на экране-заставке.   -  person Jim Mischel    schedule 18.07.2014
comment
@AwkwardCoder Я не могу найти «Экран-заставку (WPF)» при добавлении новых элементов. Я использую VS Express 2013.   -  person TheBlindSpring    schedule 18.07.2014
comment
это альтернативный способ сделать это msdn.microsoft .com/en-us/library/cc656886(v=vs.110).aspx   -  person AwkwardCoder    schedule 18.07.2014


Ответы (1)


см. MSDN Делегат MethodInvoker (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
        }
    }
person khan    schedule 17.07.2014
comment
Вы говорите, что это избавит от ошибки доступа? - person TheBlindSpring; 18.07.2014
comment
так и должно быть, ты проверял? Ошибка:Вызывающий поток не может получить доступ к этому объекту, так как он принадлежит другому потоку. означает InvokeRequired. - person khan; 18.07.2014
comment
К сожалению, я не использую WinForms. Я использую WPF и размещаю элемент управления OpenTK в элементе управления узла WinForms. - person TheBlindSpring; 18.07.2014