2013-03-19 2 views
1

Я пытаюсь загрузить несколько изображений async в ui.Создание и обновление элементов пользовательского интерфейса Async Wpf

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

Когда я помещал создание bitmapimage также в метод Dispatcher.Invoke, код работает. Но, очевидно, мне нужна тяжелая работа (создание растрового изображения), выполненная в протекторе, а не в вызове.

Я пробовал несколько решений, включая фонаря, но я не могу заставить его работать. Сейчас у меня есть следующий код:

private void Window_ContentRendered(object sender, EventArgs e) 
{ 
    Thread loadThread = new Thread(new ThreadStart(LoadImagesAsync)); 
    loadThread.Start(); 
} 

private void LoadImagesAsync() 
{ 
    IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES); 

    for (int i = 0; i < NUMBER_OF_IMAGES; i++) 
    { 
     var bitm = new BitmapImage(new Uri(images.ElementAt(i)));     

     this.Dispatcher.Invoke(() => 
     { 
      Grid grid = (Grid)grd_photoBox.Children[i]; 

      var rectangle = (from e in grid.Children.OfType<Rectangle>() 
           where e is Rectangle 
           select e).First(); 

      ImageBrush brush = new ImageBrush(bitm); 

      rectangle.Fill = brush; 
     }); 
    } 
} 

я получаю следующее исключение:

The calling thread cannot access this object because a different thread owns it. 

Любые улики?

+0

Можете ли вы описать, как это «не работает», когда вы кладете создание Bitmap вне Invoke? – Kohanz

+0

Исправлено недопустимое исключение операции, я отредактировал свой вопрос – middelpat

+0

Предлагаю взглянуть на это: http://stackoverflow.com/questions/1924408/invalid-cross-thread-access-issue – Kohanz

ответ

3

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

bitm.DecodePixelWidth = 200; 
bitm.DecodePixelHeight = 100; 

private void LoadImagesAsync() 
     { 
      IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES); 

      for (int i = 0; i < NUMBER_OF_IMAGES; i++) 
      { 
       int j = i; 
       var bitm = new BitmapImage(); 

       bitm.BeginInit(); 
       bitm.CacheOption = BitmapCacheOption.OnLoad; 
       bitm.UriSource = new Uri(images.ElementAt(i)); 
       bitm.DecodePixelWidth = 200; 
       bitm.DecodePixelHeight = 100; 
       bitm.EndInit(); 

       ImageBrush brush = new ImageBrush(bitm); 
       brush.Freeze(); 

       this.Dispatcher.BeginInvoke(new Action(() => 
       { 
        Grid grid = (Grid)grd_photoBox.Children[j]; 

        var rectangle = (from e in grid.Children.OfType<Rectangle>() 
             where e is Rectangle 
             select e).First(); 

        rectangle.Fill = brush; 
       })); 
      } 
     } 
+1

Будьте осторожны с установкой 'DecodePixelWidth' или' DecodePixelHeight', так как это может ухудшить производительность в определенных сценариях. См. Примечания [здесь] (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.decodepixelwidth.aspx): 'кодеки JPEG и Portable Network Graphics (PNG) изначально декодируются изображение до указанного размера; другие кодеки декодируют изображение в исходном размере и масштабируют изображение до требуемого размера ». И вы не должны устанавливать оба значения, если хотите сохранить собственное соотношение сторон изображения. – Clemens

+0

Можно также отметить, что если необходимо вызвать метод, помеченный как async, тогда действие должно быть также помечено как async, 'new Action (async() =>' – GaelSa

0

Я пробовал под кодом и работает для меня.

Task<IEnumerable<string>>.Factory.StartNew(() => System.IO.Directory.GetFiles(
      imagePath, 
      "*.jpg")). 
      ContinueWith(task => 
         { 
          foreach (var item in task.Result) 
          { 
           this.Dispatcher.BeginInvoke((Action)(() => 
           { 
            var img = new Image 
                { 
                 Source = 
                  new BitmapImage(
                  new Uri(item)) 
                }; 
            LayoutRoot.Children.Add(img); 

           })); 

          } 
         }); 

LayoutRoot - это моя сетка в xaml.

Надеюсь, это поможет.

+0

Благодарим вас за ответ. Он работает, но все же растровое изображение создается в uri в uri. Это приводит к созданию растрового изображения в потоке пользовательского интерфейса. Использование больших изображений по-прежнему вызывает блокировку пользовательского интерфейса – middelpat

1

Хитрость freeze растровое изображение, позволяющее получить доступ из другого потока. Поэтому вам также необходимо убедиться, что растровое изображение загружается сразу при создании, поскольку поведение по умолчанию - это лениво.

var bitm = new BitmapImage(); 
bitm.BeginInit(); 
bitm.CacheOption = BitmapCacheOption.OnLoad; // load immediately 
bitm.UriSource = new Uri(images.ElementAt(i)); 
bitm.EndInit(); 
bitm.Freeze(); 
+0

По умолчанию используется «BitmapCacheOption.Default», который соответствует [MSDN] (http://msdn.microsoft.com/en-us/library/system.windows.media. imaging.bitmapcacheoption.aspx) «Кэш всего изображения в память». – SynerCoder

+0

@SynerCoder См. раздел «Примечания» [здесь] (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging. bitmapimage.cacheoption.aspx). Хотя он описывает поведение при загрузке изображения из потока, он обычно применим. И [здесь] (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapcacheoption.aspx) вы можете прочитать, что «OnLoad» кэширует все изображение в память ** на время загрузки ** ", в отличие от« кэширует все изображение в память »для« По умолчанию ». – Clemens

+0

@SynerCoder Однако в конечном итоге вам не нужно применять флаг здесь, так как изображения загружаются из файла, что, как представляется, выполняется немедленно. Вы можете проверить свойство [IsDownloading] (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.isdownloading.aspx), чтобы узнать, загружено ли изображение или нет. , Пока он загружается, вы не можете его заморозить. – Clemens