Я столкнулся с проблемой отображения изображения из Интернета в моем приложении WPF:
Я использовал BitmapImage
для этой задачи. Моя первая попытка состояла в том, чтобы выполнить его в потоке пользовательского интерфейса, но я быстро понял, что это не так, поскольку приложение перестало отвечать до тех пор, пока изображение не было полностью загружено. Моя вторая попытка состояла в том, чтобы использовать BackgroudWorker
:
var worker = new BackgroundWorker();
worker.DoWork += worker_LoadImage;
worker.RunWorkerCompleted+=worker_RunWorkerCompleted;
worker.RunWorkerAsync(someURI);
и рабочие функции:
private void worker_LoadImage(object sender, DoWorkEventArgs e)
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnDemand;
image.UriSource = e.Argument as Uri;
image.DownloadFailed += new EventHandler<ExceptionEventArgs>(image_DownloadFailed);
image.EndInit();
e.Result = image;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//if I understand correctly, this code runs in the UI thread so the
//access to the component image1 is valid.
image1.Source = e.Result as BitmapImage;
}
после этого я все еще получил InvalidOperationException: «Вызывающий поток не может получить доступ к этому объекту, потому что им владеет другой поток». Я немного изучил и обнаружил, что, поскольку BitmapImage
равно Freezable
, мне нужно вызвать Freeze
перед доступом к объекту из другого потока. Итак, я попытался заменить последнюю строку в worker_LoadImage на:
image.Freeze();
e.Result = image;
Но затем я получил исключение, что мое изображение не может быть заморожено, я обнаружил, что это, вероятно, потому, что изображение не было загружено, когда я пытался вызвать Freeze()
. Поэтому я добавил следующий код для создания образа:
image.DownloadCompleted += image_DownloadCompleted;
где:
void image_DownloadCompleted(object sender, EventArgs e)
{
BitmapImage img = (BitmapImage)sender;
img.Freeze();
}
Итак, теперь мы подошли к главному вопросу: Как заставить фоновый рабочий процесс ждать, пока изображение не будет полностью загружено и не будет запущено событие?
Я пробовал много вещей: зацикливание, пока isDownloading изображения истинно, Thread.Sleep, Thread.Yield, семафоры, дескрипторы ожидания событий и многое другое. Я не знаю, как загрузка изображения на самом деле работает за кулисами, но что происходит, когда я пробую один из описанных выше методов, так это то, что загрузка изображения никогда не заканчивается (isDownloading зависает на True)
Есть ли лучший и более простой способ выполнить довольно простую задачу, которую я пытаюсь выполнить?
Некоторые вещи, на которые стоит обратить внимание:
этот ответ действительно работает, но только один раз: когда я пытаюсь загрузить другое изображение, он говорит, что диспетчер закрыт. Даже прочитав немного о Dispatchers, я не очень понимаю, как OP достиг этого или можно ли расширить решение для более чем одного изображения.
Когда я помещаю окно сообщения до того, как рабочий выходит из своей функции DoWork, я нажимаю «ОК», и появляется изображение, которое означает, что загрузка продолжалась, пока окно сообщения было открыто и завершено до того, как я нажал «ОК».
image1.Source = new BitmapImage(someURI);
. Чтобы выполнить загрузку всего изображения в отдельном потоке, см. этот ответ. - person Clemens   schedule 17.12.2014