Xamarin.Forms Carousel – Part 3: Reloading the Carousel’s content from a WebService

I’m on an exciting journey, getting up to speed with Xamarin.Forms. Being mostly a ASP.NET developer since more than a decade, i used some great resources out there to learn the concepts of Xamarin.Forms (using the fantastic preview chapters of Charles Petzold’s book) as well as best practices for a MVVM/IOC based architecture. For the latter the wonderful blog „Adventures in Xamarin Forms“ by Jonathan Yates was an indispensable resource full of insights and creative inspiration.

This is part 3 of the series „Creating a Xamarin.Forms Carousel“

Part 1: The basic parts
Part 2: Converting the pieces into a MVVM/XAML architecture
Part 3: Reloading the Carousel’s content from a WebService
Part 4: Design-Fun in XAML

 

In my last post i converted Chris Riesgo’s Recipe for a Xamarin.Forms Carousel into a XAML/MVVM based solution. In the demo i created some simple ContentViews, loaded in the Carousel.

Now, why not have some more fun and check how our component behaves when we really load some images from the web, thus changing the ItemsSource on the fly. I want to display some images from Flickr, and also change the number of images in the Carousel to check if the NavigationIndicator properly reflects the change in content.

So let’s fire up the Flickr Api to fetch soume mountain images and see what we get:

https://api.flickr.com/services/feeds/photos_public.gne?format=json&tags=mountain

 

 

That’s fine, but this is no valid JSON, so in order to make it valid we will have to modify it, e.g. like this:

 

With this modified JSON i am able to create some model classes for deserializing the results. I used Visual Studio’s „Paste JSON as classes“ feature to create the model classes from this JSON sample data, which i then added to my PCL’s models folder (back in Xamarin Studio):

 

Next step is to create an interface to access the Flickr Api. I will keep this simple, as i just want to load images with a certain tag.
Thus i defined a method signature that returns an array of Flickr Item objects, taking the requested tags and a count as parameters:

 

The implementation of the service is just standard HttpClient code with some fiddling to make the returned Flickr JSON valid, so it can be deserialized using JSON.NET. I’ve left out some real-world error handling to keep things simple:

 

 

So the basic classes to load our Flickr images are now in place and we can start integrating them into our Carousel-demo.
I want to be able to initiate the loading of the Flickr images from my Demo page, so – getting back to the XAML of my DemoPage –  i include a Load-Button after my Prev and Next-buttons, which is bound to a LoadPhotosFromFlickrCommand:

 

To make this work, we need to implement this command. As the BindingContext is set to Carousel, which is the CarouselDemoViewModel, we will extend this class. As mentioned before, my overall architecture is based on MVVM and IOC, heavily embracing Jonathan Yates elegant solution. Until now i didn’t care too much about Dependency Injection in this post, as our Carousel ViewModels were quite self contained. But now, we want to give the ViewModel access to our FlickrService and thus we are injecting the FlickrService into our ViewModel’s constructor. Our IOC container (AutoFAC) will automatically provide an instance of our service, once we registered it. If you never dealt with IOC (Inversion Of Control, aka Dependency Injection) before, i highly recommend reading Jonathan’s blog, especially the part about Dependency injection:

http://adventuresinxamarinforms.com/2014/11/17/creating-a-xamarin-forms-application-part-4-dependency-injection/

Our CarouselDemoViewModel now looks like that:

 

 

You see that the LoadPhotosFromFlickrCommand is initialized in the constructor to call the LoadPhotosFromFlickr method. This method takes the injected _feedservice interface and calls the GetImagesAsync method for the tag „mountain“ and with a maximum number of 8 result elements. It then creates a new List<CarouselItemViewModel> object and then sets the CarouselPages property to that new List of items.

Because the Carousel’s ItemsSource property is bound to the CarouselPages, the Carousel now automatically should update its contents.

As the CarouselDemoViewModel now needs to get the FeedService injected, we have to reflect this change in our PageViewModel, where we are creating an instance of the CarouselDemoViewModel and let now do the IOC container the job of instantiating the ViewModel for us:

 

 

OK, let’s fire up the app and see how it works.

The app loads with our static set of images. Scrolling one image to the right, we get:

Xamarin.Forms Carousel DemoPage with CarouselImageView scrolled

Carousel DemoPage with CarouselImageView scrolled

 

Now it’s Flickr time. We click our new Button and after a moment our images reload and the SelectedIndex switches back to 0. This is the behavior that makes sense to me, that’s why i changed the last statement in the CarouselLayout.cs ItemsSourceChanged method:

 

 

Also the NavigationIndicator now reflects the new number of images – still perfectly centered on our screen. Here’s a video of the iOS app in action:

 

You see how easy it now is to integrate the Carousel in a clean, pure MVVM solution for a cross platform Xamarin.Forms app.
Cross platform? OK – time to see how this works in the Android version of the App:

 

Strange. While the manual scrolling and the reloading of the items from Flickr works just like they should, the automatic scrolling, driven by the buttons behaves buggy. There are two issues:
  1. The scrolling itself always starts the animation from the first item in the ScrollView, which is clearly not as intended
  2. The SelectedIndex property doesn’t get updated
Let’s look at the Scrolling issue first. This works fine on iOS so it must be a platform specific issue. When i do the button-driven scrolling, i am calling the ScrollToIndexCommand in my CarouselViewDots  class. This is directly calling the ScrollToAsync method of the CarouselLayout classes underlying ScrollView:

 

After some investigations it seems to me that the Android version of the ScrollToIndexCommand is not ready to scroll from somewhere in the middle to some other position, but is just made to do some initial scrolling from start to a certain position.
Turning off the animation helped, so i changed the above method and turned off animation for Android:

 

Now to the second issue, the SelectedIndex property, which is a bindable property of the CarouselLayout class. It is updated automatically when the SelectedItem changes:

 

But this property isn’t only updated in the platform-independent CarouselLayout class, but also in the NativeScrolled method of the iOS-specific renderer, which is registered as a handler of the native ScrollView’s Scrolled event:

 

 

The iOS version of ScrollView offers an event that is also fired when the ScrollView is scrolled by calling the ScrollToAsync method, which is why the button-driven scrolling is working fine in iOS.
For Android’s ScrollView no suitable event seems to exist at this time (Xamarin.Forms 1.5.0). So we have to take care of updating the SelectedIndex property when we call the ScrollToAsync method  ourselves and we do this after our awaited call to ScrollToAsync in the CarouselViewDots XAML component.

 

With these small fixes, our Android version now works as expected:

Great. Now we have tested our Carousel component on both targeting platforms.
You see, the sooner you test on all platforms, the sooner you catch platform-specific issues.
Note: With the release of Xamarin.Forms 1.5.1 the Android ScrollView-bug has been fixed. So there is no more need to switch off animation when doing a ScrollToAsync.
Xamarin Forms does a great job in keeping you away  from platform-specific code as far as possible, but for advanced features you will sooner or later need some platform renderers. And some platform testing.
In my next post i plan to enhance my CarouselImageView, creating some really nice visual layout.
Stay tuned.