2014-01-25 5 views
0

Я пытаюсь сделать загрузку изображений в разных потоках, но изображение никогда не обновляется.Использование Task.Factory в классе изображений

public class MyImage : System.Windows.Controls.Image 
{ 
    public MyImage() 
    { 
    this.Loaded += new RoutedEventHandler(MyImage_Loaded); 
    } 
    void MyImage_Loaded(object sender, RoutedEventArgs e) 
    { 
    //[email protected]"c:\test.jpg"; 
    var t = Task<ImageSource>.Factory.StartNew(() => GetImage(mypath)); 
    Source = t.Result; 
    } 

Error on Source

следующие работы, но это поток пользовательского интерфейса:

Source = GetImage(mypath); 

Я попробовал то же самое с BackgroundWorker, но результат тот же. Возможно ли это сделать без MVVM?

+0

Почему вы используете задачу, если просто заблокируете основной поток, вызвав свойство Result? –

+0

Что не работает? Есть ли исключение, ничего не происходит, что? Что такое «mypath»? –

+0

@PeterRitchie mypath - путь к изображению. Не исключение. Если я попробую var t1 = Задача .Factory.StartNew (() => GetImage (mypath)) .ContinueWith (antecendent => { Источник = antecendent.Result; }); Я получаю «Исключение типа« System.InvalidOperationException »произошло в WindowsBase.dll, но не обрабатывалось в коде пользователя. Дополнительная информация: вызывающий поток не может получить доступ к этому объекту, потому что ему принадлежит другой поток». – Daniel

ответ

2

Поскольку вы создаете ImageSource на другом потоке, то один вы хотите использовать его на вы получаете

Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет

исключение, и для решения вашей проблемы вы должны позвонить Freeze() на свой ImageSource. Однако, даже если вы загрузите изображение на другом потоке ваш код блокирует поток пользовательского интерфейса, пока он не будет готов:

var t = Task<ImageSource>.Factory.StartNew(() => GetImage(mypath)); 
Source = t.Result; //this line blocks UI thread until Result is ready 

Если вы хотите, чтобы избежать этого изменить его на:

Task.Factory.StartNew(() => 
{ 
    var source = GetImage(mypath); 
    source.Freeze(); 
    this.Dispatcher.Invoke(() => this.Source = source); 
}); 

Это должно загрузить изображение на другом потоке и update Source, когда он готов без блокировки нити пользовательского интерфейса

+0

Спасибо вам большое! Замораживание было ключевым (слово, которое не приходит в голову в наши дни). Я также подумал, что без Invoke он будет ждать, пока пользовательский интерфейс не захочет обновить себя, и одновременно будет обновлять несколько изображений. Task Factory отлично работает, но легко сделать небольшую ошибку и свести на нет выгоду от запуска кода в другом потоке. Теперь он отлично работает! – Daniel

+0

Легко получить эту многопоточность неправильно. Вы можете использовать свой код, если, например, у вас будет что-то другое сходной длины между созданием 'Task' и ожиданием' Result' – dkozl

0

Попробуйте вернуть байт [] или поток из GetImage (или из его результата), затем используйте Dispatcher.Invoke, чтобы вызвать помощника в потоке пользовательского интерфейса, который восстанавливает изображение из байта [] или потока и обновляет источник MyImage.

Это мой рабочий POC. Вы хотите изучить его для правильной утилизации потока и так далее. (Примечание: disp является грузоотправитель на «пост» в UI)

Task.Factory.StartNew(() => 
       { 
        var result = GetImage(); 
        var bitmap = new BitmapImage(); 
        var stream = result;  
        bitmap.BeginInit(); 
        bitmap.CacheOption = BitmapCacheOption.OnLoad; 
        bitmap.StreamSource = stream; 

        bitmap.EndInit(); 
        bitmap.Freeze(); 
        stream.Dispose(); 
        disp.Invoke(new Action(()=> MyImage.Source = bitmap)); 
       }); 

И GetImage():

private MemoryStream GetImage() 
    { 
     System.Threading.Thread.Sleep(35000); 
     var filePath = @"C:\temp\2013-01-08-235341.jpg"; 
     MemoryStream memoryStream = null; 
     if (File.Exists(filePath)) 
     { 
      memoryStream = new MemoryStream(); 

      byte[] fileBytes = File.ReadAllBytes(filePath); 
      memoryStream.Write(fileBytes, 0, fileBytes.Length); 
      memoryStream.Position = 0; 
     } 

     return memoryStream; 
    } 
Смежные вопросы