Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImageGalleryControl not triggering

I'm attempting to download an image in bytes from a server, but the image won't display. I get a proper byte array and resize it. It works adding picture from the camera but doesn't work when adding them from the internet.

I've confirmed that the image is saved correctly, and downloaded properly as I can copy the byte Array and display it using the byte array string.

I found the problem comparing the two methods while debugging, and in the execturepickcommand it triggers my "ItemSourceChanged" method but it doesn't trigger with the AddImages method.

The Collection

public class ImageGalleryPageModel {     public ObservableCollection<ImageModel> Images     {         get { return images; }     }      private ObservableCollection<ImageModel> images = new ObservableCollection<ImageModel>(); } 

This works adding the Pictures from this class

private async Task ExecutePickCommand() {     MediaFile file = await CrossMedia.Current.PickPhotoAsync();      if (file == null)         return;      byte[] imageAsBytes;     using (MemoryStream memoryStream = new MemoryStream())     {         file.GetStream().CopyTo(memoryStream);         file.Dispose();         imageAsBytes = memoryStream.ToArray();     }      if (imageAsBytes.Length > 0)     {         IImageResizer resizer = DependencyService.Get<IImageResizer>();         imageAsBytes = resizer.ResizeImage(imageAsBytes, 1080, 1080);          ImageSource imageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));         Images.Add(new ImageModel { Source = imageSource, OrgImage = imageAsBytes });     } } 

Then I download the images and put them into the Collection,

private void AddTheImages(int imageIssueId) {     var imageData = App.Client.GetImage(imageIssueId);      byte[] imageAsBytes = imageData.Item1;      if (imageAsBytes.Length > 0)     {         IImageResizer resizer = DependencyService.Get<IImageResizer>();         imageAsBytes = resizer.ResizeImage(imageAsBytes, 1080, 1080);          ImageSource imageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));         ImageGalleryViewModel.Images.Add(new ImageModel { Source = imageSource, OrgImage = imageAsBytes });     } } 

Xaml

<freshMvvm:FreshBaseContentPage NavigationPage.HasNavigationBar="False"                                  xmlns="http://xamarin.com/schemas/2014/forms"                                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"                                 xmlns:freshMvvm="clr-namespace:FreshMvvm;assembly=FreshMvvm"                                 xmlns:converters="clr-namespace:ASFT.Converters;assembly=ASFT"                                 xmlns:controls="clr-namespace:ASFT.Controls;assembly=ASFT"                                 x:Class="ASFT.Pages.IssuePage"                                  Padding="4,25,4,4"                                  x:Name="IssuePages">     ...     <!--PictureGallery-->     <Label Text="IMAGES"             HorizontalTextAlignment="Start"             VerticalTextAlignment="Center"            Style="{StaticResource Labelfont}"             TextColor="White" />     <Grid BindingContext="{Binding ImageGalleryViewModel}">         <Grid.RowDefinitions>             <RowDefinition Height="128" />             <RowDefinition Height="*" />         </Grid.RowDefinitions>         <controls:ImageGalleryControl Grid.Row="0"                                        ItemsSource="{Binding Images}">             <controls:ImageGalleryControl.ItemTemplate>                 <DataTemplate>                     <Image Source="{Binding Source}"                             Aspect="AspectFit">                         <Image.GestureRecognizers>                             <TapGestureRecognizer                                 Command="{Binding Path=BindingContext.PreviewImageCommand, Source={x:Reference IssuePages}}"                                 CommandParameter="{Binding ImageId}" />                         </Image.GestureRecognizers>                     </Image>                 </DataTemplate>             </controls:ImageGalleryControl.ItemTemplate>         </controls:ImageGalleryControl>         <Grid Grid.Row="1">             <Grid.ColumnDefinitions>                 <ColumnDefinition Width="*" />                 <ColumnDefinition Width="*" />             </Grid.ColumnDefinitions>             <Button Grid.Column="0"                      Text="Add photo"                      Command="{Binding CameraCommand}" />             <Button Grid.Column="1"                      Text="Pick photo"                      Command="{Binding PickCommand}" />         </Grid>     </Grid>     <Label Grid.Column="0"             Grid.Row="3"             Grid.ColumnSpan="3"             Text="{Binding ImageText}"             HorizontalTextAlignment="Center"             VerticalTextAlignment="Center"             TextColor="White" />     ... </freshMvvm:FreshBaseContentPage> 

And this is the Control, it is the itemsourcechanged which is what is not triggering.

    private readonly StackLayout imageStack;     public ImageGalleryControl()     {         this.Orientation = ScrollOrientation.Horizontal;          imageStack = new StackLayout         {             Orientation = StackOrientation.Horizontal         };          this.Content = imageStack;     }      public new IList<View> Children     {         get { return imageStack.Children; }     }      public static readonly BindableProperty ItemsSourceProperty =         BindableProperty.Create<ImageGalleryControl, IList>         (             view => view.ItemsSource,             default(IList),             BindingMode.TwoWay,             propertyChanging: (bindableObject, oldValue, newValue) =>              {                 ((ImageGalleryControl)bindableObject).ItemsSourceChanging();             },             propertyChanged: (bindableObject, oldValue, newValue) =>              {                 ((ImageGalleryControl)bindableObject).ItemsSourceChanged(bindableObject, oldValue, newValue);             }         );      public IList ItemsSource     {         get { return (IList)GetValue(ItemsSourceProperty); }         set { SetValue(ItemsSourceProperty, value); }     }      private void ItemsSourceChanging()     {         if (ItemsSource == null)             return;     }      private void CreateNewItem(IList newItem)     {         View view = (View)ItemTemplate.CreateContent();         if (view is BindableObject bindableObject)             bindableObject.BindingContext = newItem;         imageStack.Children.Add(view);     }      private void ItemsSourceChanged(BindableObject bindable, IList oldValue, IList newValue)     {         if (ItemsSource == null)             return;          if (newValue is INotifyCollectionChanged notifyCollection)         {             notifyCollection.CollectionChanged += (sender, args) =>              {                 if (args.NewItems != null)                 {                     if (args.NewItems.Count > 0)                     {                         foreach (object newItem in args.NewItems)                         {                             View view = (View)ItemTemplate.CreateContent();                             if (view is BindableObject bindableObject)                                 bindableObject.BindingContext = newItem;                             imageStack.Children.Add(view);                         }                     }                 }                 else                 {                     imageStack.Children.Clear();                     foreach (object item in ItemsSource)                     {                         View view = (View)ItemTemplate.CreateContent();                         BindableObject bindableObject = (BindableObject) view;                         if (bindableObject != null)                             bindableObject.BindingContext = item;                         imageStack.Children.Add(view);                     }                 }                 if (args.OldItems != null)                 {                     // not supported                 }             };         }     }      public DataTemplate ItemTemplate     {         get;         set;     }      public static readonly BindableProperty SelectedItemProperty =         BindableProperty.Create<ImageGalleryControl, object>         (             view => view.SelectedItem,             null,             BindingMode.TwoWay,             propertyChanged: (bindable, oldValue, newValue) =>              {                 ((ImageGalleryControl)bindable).UpdateSelectedIndex();             }         );      public object SelectedItem     {         get { return GetValue(SelectedItemProperty); }         set { SetValue(SelectedItemProperty, value); }     }      private void UpdateSelectedIndex()     {         if (SelectedItem == BindingContext)             return;          SelectedIndex = Children             .Select(c => c.BindingContext)             .ToList()             .IndexOf(SelectedItem);      }      public static readonly BindableProperty SelectedIndexProperty =         BindableProperty.Create<ImageGalleryControl, int>         (             carousel => carousel.SelectedIndex,             0,             BindingMode.TwoWay,             propertyChanged: (bindable, oldValue, newValue) =>              {                 ((ImageGalleryControl)bindable).UpdateSelectedItem();             }         );      public int SelectedIndex     {         get { return (int)GetValue(SelectedIndexProperty); }         set { SetValue(SelectedIndexProperty, value); }     }      private void UpdateSelectedItem()     {         SelectedItem = SelectedIndex > -1 ? Children[SelectedIndex].BindingContext : null;     } } 
like image 918
JsonDork Avatar asked Apr 04 '18 11:04

JsonDork


1 Answers

  1. Try to Raise Propertychanged event for Images Property like : PropertyChanged(nameof(Images)).
  2. Then to verify you are on the same ViewModel instance, you can subscribe on BindingContextChanged event in your page and verify either your VM object is changing or not.
  3. I would suggest using ObservableCollection as: public ObservableCollection<> Images {get;set;} = new ObservableCollection<>();

with a generic ImageModel. You don't need a private field, it doesn't make a lot of sense.

like image 109
Aleksandr Smyk Avatar answered Sep 19 '22 18:09

Aleksandr Smyk