Как открыть окно в новой теме? - PullRequest
10 голосов
/ 22 января 2012

У меня есть окно параметров и окно, которое отображает цвет на основе этих параметров и данных Kinect. Пока что все в одном потоке (насколько я знаю; я не делал никаких потоков).

Теперь я добавляю опцию, чтобы открыть окно просмотра, которое нужно будет обновлять с минимально возможной задержкой. Все это влечет за собой создание окна и его показ:

viewer = new SkeletalViewer.MainWindow();
viewer.Show();

Когда это событие запускается, цветное окно перестает отображать цвета (то есть событие, которое запускается 30 раз в секунду в главном потоке, прекращает срабатывание), но средство просмотра отображается отлично. Я хочу, чтобы окно просмотра и цветное окно были обновлены.

Из прочтения других вопросов звучит так, что решение состоит в том, чтобы создать зрителя в новой теме Однако с этим я сталкиваюсь с множеством проблем.

Это срабатывает, когда я нажимаю кнопку, чтобы открыть средство просмотра:

private void launchViewerThread_Click(object sender, RoutedEventArgs e)
    {
        Thread viewerThread = new Thread(delegate()
        {
            viewer = new SkeletalViewer.MainWindow();
            viewer.Dispatcher.Invoke(new Action(delegate() 
                {
                    viewer.Show();
                }));
        });

        viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception
        viewerThread.Start();

    }

Независимо от того, вызову ли я просто viewer.Show () или Invoke (), как указано выше, строка вызывает исключение: Невозможно использовать объект DependencyObject, принадлежащий другому потоку, чем его родительский Freezable. Вот насколько я понимаю Invoke (): он обращается к диспетчеру зрителя, который знает, в каком потоке работает объект, и может затем вызывать методы из этого потока.

Должен ли я пытаться поместить эту программу просмотра в новую тему? Проблема даже в вопросе нитей? Пользователь не будет взаимодействовать со зрителем.

Кто-нибудь знает, почему это не работает? Спасибо за помощь.

Ответы [ 3 ]

18 голосов
/ 22 января 2012

Вам нужно вызвать Show() в том же потоке, в котором создано окно - вот почему вы получаете сообщение об ошибке.Затем вам также нужно запустить новый экземпляр Dispatcher, чтобы среда выполнения управляла окном.

private void launchViewerThread_Click(object sender, RoutedEventArgs e)
{
    Thread viewerThread = new Thread(delegate()
    {
        viewer = new SkeletalViewer.MainWindow();
        viewer.Show();
        System.Windows.Threading.Dispatcher.Run();
    });

    viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception
    viewerThread.Start();
}

См. Пример «Несколько окон / Несколько потоков» по ​​адресу: http://msdn.microsoft.com/en-us/library/ms741870.aspx

1 голос
/ 29 января 2014

Итак, я столкнулся с подобной проблемой, когда новое окно не удалось открыть в новом потоке. Исключением было «невозможно использовать объект зависимости, принадлежащий другому потоку».

Проблема закончилась тем, что окно использовало глобальный ресурс (кисть фона). Как только я заморозил ресурс кисти, окно загрузилось нормально.

0 голосов
/ 22 января 2012

Я не уверен, что это решит вашу проблему, но вы можете попробовать создать процесс потока (чтобы открыть окно просмотра), который выполняется в другом потоке, а затем иметь dispatcher.beginInvoke для обновления главного окна,

Вот код:

    in the constructor register this
    public MainWindow()
    { 
       UpdateColorDelegate += UpdateColorMethod;
    } 

    // delegate and event to update color on mainwindow 
    public delegate void UpdateColorDelegate(string colorname);
    public event UpdateColorDelegate updateMainWindow;

    // launches a thread to show viewer
    private void launchViewerThread_Click(object sender, RoutedEventArgs e)
    {
        Thread t = new Thread(this.ThreadProc);
        t.Start();
    }

    // thread proc
    public void ThreadProc()
    {
       // code for viewer window
       ...
       // if you want to access any main window elements then just call DispatchToMainThread method
       DispatchToUiThread(color);   
    } 

    // 
    private void DispatchToUiThread(string color)
    {
      if (updateMainWindow != null)
      {
        object[] param = new object[1] { color};
        Dispatcher.BeginInvoke(updateMainWindow, param);
      }
    }

    // update the mainwindow control's from this method
    private void UpdateColorMethod(string colorName)
    {
       // change control or do whatever with main window controls
    } 

С этим вы можете обновить элементы управления главного окна, не замораживая его, дайте мне знать, если у вас есть какие-либо вопросы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...