Что такое родительский заморозить? Что означает эта ошибка? - PullRequest
10 голосов
/ 14 мая 2009

Я получаю эту ошибку:

Невозможно использовать объект DependencyObject, принадлежащий другому потоку, чем его родительский Freezable

Что это вообще значит? Это на английском? Родитель заморожен или просто замораживается? Любой способ сделать родителя не замораживаемым, если это устранит ошибку?

Что происходит:

У меня есть два элемента управления winforms opengl в приложении WPF, и до сих пор все работало гладко (я думаю). Теперь я добавил обновление, так что когда один элемент управления winform обновляет изображение, другой должен также. Это на самом деле раньше работало, и теперь я получаю эту ошибку. При выполнении кода происходит сбой в случайных местах, что позволяет мне полагать, что это ошибка сборки мусора (то есть, какое-то обновление в другом потоке создает что-то, что собирает мусор, и эта сборка происходит в случайное время). 1009 *

Исключение перехватывается в методе основного запуска, и это исключение InvalidOperationException.

Я хватаюсь за соломинку здесь. С чего начать?

РЕДАКТИРОВАТЬ: похоже, что вызов, который вызывает проблему, это:

        if (imagePanel.InvokeRequired)
        {
            imagePanel.Invoke(new System.Windows.Forms.MethodInvoker(delegate{
                imagePanel.ClearImages();
            }));
        }
        else
        {
            imagePanel.ClearImages();
        }

Я все еще выслеживаю это; если этот ряд строк закомментирован, сбой все еще происходит, и состояние потока имеет поток «только что закончился» (отсюда и предположение о сборке мусора).

1 Ответ

13 голосов
/ 14 мая 2009

ОК, я понял это. Обычно я просто удаляю этот вопрос, но было сложно найти какую-либо информацию о том, как это исправить.

Проблема была в вызове, который выглядел так:

ImageBrush theBrush = new ImageBrush(new Bitmap(new Uri(...)));

if (labelStatus.Dispatcher.Thread == System.Threading.Thread.CurrentThread) {
    button.background = theBrush;
}
else {
   labelStatus.Dispatcher.BeginInvoke((System.Threading.ThreadStart)(delegate {
    button.background = theBrush;
   }));
}

Но! если вы это сделаете, то диспетчер сработает, а затем попытается удалить кисть, но сама кисть, очевидно, также удаляется в другом месте.

Итак, домашний урок: если вы объявите ImageBrush, то удалите его в той же теме, например:

void MyFunc(){
     ImageBrush theBrush = new ImageBrush(new Bitmap(new Uri(...)));
     button.background = theBrush;
}

if (labelStatus.Dispatcher.Thread == System.Threading.Thread.CurrentThread) {
    MyFunc();
}
else {
   labelStatus.Dispatcher.BeginInvoke((System.Threading.ThreadStart)(delegate {
       MyFunc();
   }));
}
...