Как да получите достъп до WPF обект в диспечера?

Използвам модела MVVM за разработване на WPF приложение.

Приложението зарежда captcha изображение от сървъра и го присвоява на изображение във WPF формуляра, когато е готово. Използвам BackgroundWorker, за да направя нишката вместо мен, както следва:

Когато прозорецът се зарежда, се извиква следното:

BackgroundWorker _bgWorker = new BackgroundWorker();

_bgWorker.DoWork += GetCaptchaImage;
_bgWorker.RunWorkerAsync();

Функцията GetCaptchaImage е доста проста, зарежда изображение в друга нишка:

BitmapSource _tempBitmap = GetCaptchaFromServer();

Трябва да знам как да извикам диспечера, за да присвоя този ImageSource към източника на изображение на моя прозорец. В момента се обаждам на диспечера след зареждане на _tempBitmap, както следва:

Application.Current.Dispatcher.Invoke(
new Action(() => CaptchaBitmap = _tempBitmap));

Където CaptchaBitmap е свързан с данни към моя източник на изображение.

Въпреки това, когато направя това, се хвърля InvalidOperationException и всяка препратка към _tempBitmap връща грешка в нишката на GUI. Знам го, защото имам достъп до него от GUI нишката на диспечера, когато беше създаден в BackgroundWorker нишка, но как да го заобиколя?

Помощта ще бъде високо оценена! :)


person Community    schedule 04.08.2009    source източник


Отговори (4)


Просто извикайте BitmapSource.Freeze, преди да извикате Dispatcher.Invoke

BitmapSource _tempBitmap = GetCaptchaFromServer();
_tempBitmap.Freeze();
Application.Current.Dispatcher.Invoke(
new Action(() => CaptchaBitmap = _tempBitmap));

Всички WPF обекти могат да бъдат достъпни само от нишката, която ги е създала, изключения са Dispatcher (по очевидни причини) и Freezable, след като извикате метода Freeze.

След извикване на Freeze обектът може да бъде достъпен от всяка нишка (но не може да бъде модифициран), за ваш късмет BitmapSource наследява от Freezable.

person Nir    schedule 04.08.2009
comment
През последния час си скубех косата заради този проблем. Благодаря купища! - person Jamie Love; 04.08.2009

Имах същия проблем WPF: Прехвърляне на обекти между UI Thread и Background нишка Не разбрах какво е "правилното" решение. В крайна сметка замени моя BackgroundWorker с DispatcherTimer, който ще се стартира само веднъж и това работи.

person Sharun    schedule 04.08.2009

Просто от любопитство.. Защо не направите цялото извличане и настройка на изображението в нишката на Dispatcher вместо в класа BackgroundWorker?

Dispatcher.Invoke(DispatcherPriority.Background,
    new Action(() => { CaptchaBitmap = GetCaptchaFromServer(); } )
);
person Arcturus    schedule 04.08.2009

@Arcturus, от моя опит, ако го направите, няма да получите никаква реакция на потребителския интерфейс, докато изтеглянето от сървъра не приключи...защото всъщност прекъсвате нишката на потребителския интерфейс и СЛЕД това изтегляте нещата...правих тази грешка в няколко от моите проекти и се чудя защо потребителският интерфейс не реагира....

person Community    schedule 05.08.2009
comment
Да, вярно е.. ето защо обикновено върша работните неща във фоновата нишка, така че нишката на потребителския интерфейс да привлече най-много внимание и да продължи да се актуализира.. - person Arcturus; 05.08.2009