2
Answers

Load one image at a time

none

none

7y
189
1
Hello guys,
I'm using uwp (C#) to create an app for an olympus camera.
(The camera acts as an Web server, and the comunication is over HTTP)
I have to display a huge grid with the thumbnails of the pictures and for this I have a list with the urls (strings) binded to the image list in xaml... and I have 2 issues here:
 1. The Camera accepts just a few request at a time, and with my approach, the xaml will try to load all the images at the same time.
      Is there a nice way of loading one image at a time from the xaml? I don't know... some kind of 'magic' that loads the image just after all images before are loaded :).
 
2.  Load just the images that are intro scroll view
 
Is there any way to combine this 2 issues into one super elegant solution?
My thoughts to keep track of the images loaded when I create the url list, and load the next manually, and check if the image is intro view will be the worst code ever written :))
 
I know there's something better
 
Thank you 
Answers (2)
2
Amit Gupta

Amit Gupta

NA 16.5k 25.7k 7y
As your images are fetched from an url, you can implement? async/await functionality to load images asynchronously in the code behind. This would be more effective performance wise
1
none

none

NA 110 0 7y
I can't load load hundreds of images in memory, and I wanted a way to let know the UI how to load and dispaly the images, separated from the bussiness behind, and I managed to do something with DependencyObject. Here's the code if someone needs it
 
 The dependency object
  1. public class ImageLoader : DependencyObject  
  2.     {  
  3.         static LoadOneImageAtATimeService loadOneImageService = new LoadOneImageAtATimeService>();  
  4.   
  5.         static private List imageList = new List();  
  6.   
  7.         public static readonly DependencyProperty UseOneImageAtATimeProperty =  
  8.         DependencyProperty.RegisterAttached(  
  9.           "UseOneImageAtATime",  
  10.           typeof(Boolean),  
  11.           typeof(ImageLoader),  
  12.           new PropertyMetadata(null, OnLoadOneImageAtATimeChanged)  
  13.         );  
  14.   
  15.         public static void SetUseOneImageAtATime(UIElement element, Boolean value)  
  16.         {  
  17.             element.SetValue(UseOneImageAtATimeProperty, value);  
  18.         }  
  19.   
  20.         public static Boolean GetUseOneImageAtATime(UIElement element)  
  21.         {  
  22.             return (Boolean)element.GetValue(UseOneImageAtATimeProperty);  
  23.         }  
  24.   
  25.   
  26.         static void OnLoadOneImageAtATimeChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)  
  27.         {  
  28.             if (!(target is Image))  
  29.             {  
  30.                 return;  
  31.             }  
  32.             Image image = (Image)target;  
  33.             loadOneImageService.AddImage(image);  
  34.         }  
  35.   
  36.   
  37.   
  38.     }  
 The service with the loading logic
  1. public class LoadOneImageAtATimeService  
  2.     {  
  3.         public LoadOneImageAtATimeService()  
  4.         {  
  5.   
  6.         }  
  7.   
  8.         private Queue imageList = new Queue();  
  9.         private List requestedImageList = new List();  
  10.   
  11.         public int ImagesAtATime { getset; } = 1;  
  12.   
  13.         public void AddImage(Image image)  
  14.         {  
  15.             image.DataContextChanged += new Windows.Foundation.TypedEventHandler(DataContextChanged);              
  16.         }  
  17.   
  18.           
  19.         private void TryLoadNext()  
  20.         {  
  21.             if(requestedImageList.Count >= ImagesAtATime)  
  22.             {  
  23.                 return;  
  24.             }  
  25.   
  26.             if (!imageList.Any())  
  27.             {  
  28.                 return;  
  29.             }  
  30.   
  31.             Image image = imageList.Dequeue();  
  32.             requestedImageList.Add(image);  
  33.   
  34.             ICameraImage imageContext = (ICameraImage)image.DataContext;  
  35.   
  36.             if(imageContext.Source == imageContext.Thumbnail)  
  37.             {  
  38.                 SetImageAsLoaded(image);  
  39.                 return;  
  40.             }  
  41.   
  42.             imageContext.Source = imageContext.Thumbnail;  
  43.             image.ImageOpened += new RoutedEventHandler(ImageLoaded);  
  44.         }  
  45.   
  46.         private void DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)  
  47.         {  
  48.             if(sender.DataContext == null)  
  49.             {  
  50.                 return;  
  51.             }  
  52.   
  53.             Image image = (Image)sender;  
  54.   
  55.             ((ICameraImage)image.DataContext).Source = "ms-appx:///Assets/GenericPhoto7.png";  
  56.             //image.DataContextChanged -= new Windows.Foundation.TypedEventHandler(DataContextChanged);  
  57.             imageList.Enqueue(image);  
  58.             TryLoadNext();  
  59.         }  
  60.   
  61.         private void ImageLoaded(object sender, RoutedEventArgs args)  
  62.         {  
  63.             Image image = (Image)sender;  
  64.             image.ImageOpened -= new RoutedEventHandler(ImageLoaded);  
  65.   
  66.             SetImageAsLoaded(image);  
  67.         }  
  68.   
  69.         private void SetImageAsLoaded(Image image)  
  70.         {  
  71.             requestedImageList.Remove(image);  
  72.             TryLoadNext();  
  73.         }  
  74.     }  
 and to use this all we need is to add a new attribute to the image
 
  1. <Image Width="100"  
  2.                            Height="100"  
  3.                            Source="{Binding Path=Source}"     
  4.                            Stretch="UniformToFill"  
  5.                            c:ImageLoader.UseOneImageAtATime="True"  
  6.                            />