Working with CarouselView in Xamarin Forms

microsoft xamarin heros c# iOS Android UWP

Xamarin.Forms code runs on multiple platforms – each of which has its own filesystem. This means that reading and writing files is most easily done using the native file APIs on each platform. Alternatively, embedded resources are a simpler solution to distribute data files with an app.

Run application on Windows10

CarouselView

CarouselView is available in Xamarin.Forms 4.3. However, it is currently experimental and can only be used by adding the following line of code to your AppDelegate class on iOS, or to your MainActivity class on Android, before calling Forms.Init:

Forms.SetFlags("CollectionView_Experimental");

Prerequisites

  • Visual Studio 2017 or later (Windows or Mac)
  • Xamarin.Forms 4.3 Updated

Setting up a Xamarin.Forms Project

Start by creating a new Xamarin.Forms project. You wíll learn more by going through the steps yourself.

Visual Studio 2019 has more options in the opening window. Clone or check out the code from any repository or, open a project or solution for your computer.

Now, you need to click “Create a new project”.

Now, filter by Project Type: Mobile

Choose the Mobile App (Xamarin. forms) project under C# and Mobile.

Name your app. You probably want your project and solution to use the same name as your app. Put it on your preferred location for projects and click “Create”.

Now, select the blank app and target platforms – Android, iOS and Windows (UWP).

Subsequently, go to the solution. In there, you get all the files and sources of your project (.NET Standard). Now, select the XAML page and double-click to open the MainPage.Xaml page.

You now have a basic Xamarin.Forms app. Click the Play button to try it out.

Android implementation

MainActivity.cs

protected override void OnCreate(Bundle savedInstanceState)
{
    TabLayoutResource = Resource.Layout.Tabbar;
    ToolbarResource = Resource.Layout.Toolbar;

    base.OnCreate(savedInstanceState);

    global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
    Xamarin.Essentials.Platform.Init(this, savedInstanceState);
    global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
    LoadApplication(new App());
}

iOS implementation

AppDelegate.cs

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());

    return base.FinishedLaunching(app, options);
}

UWP

App.xaml.cs

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                Xamarin.Forms.Forms.SetFlags("Shell_UWP_Experimental", "CollectionView_Experimental");
                Xamarin.Forms.Forms.Init(e);

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

Common project

Create a Model to Bind the Collections.

/// <summary>
/// Class AnimalModel.
/// </summary>
public class AnimalModel
{
    /// <summary>
    /// Gets or sets the title.
    /// </summary>
    /// <value>The title.</value>
    public string Title { get; set; }
    /// <summary>
    /// Gets or sets the image path.
    /// </summary>
    /// <value>The image path.</value>
    public ImageSource ImagePath { get; set; }
    /// <summary>
    /// Gets or sets the description.
    /// </summary>
    /// <value>The description.</value>
    public string Description { get; set; }
}

Now, Bind the Collection to CarouselView. Similar CollectionView and ListView.

using CarouselViewChallenge.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;

namespace CarouselViewChallenge.ViewModels
{
    /// <summary>
    /// Class CarouselPageViewModel.
    /// Implements the <see cref="System.ComponentModel.INotifyPropertyChanged" />
    /// </summary>
    /// <seealso cref="System.ComponentModel.INotifyPropertyChanged" />
    public class CarouselPageViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        /// <returns></returns>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// The animal
        /// </summary>
        private ObservableCollection<AnimalModel> _animal;
        /// <summary>
        /// The page title
        /// </summary>
        private string _pageTitle;
        /// <summary>
        /// Initializes a new instance of the <see cref="CarouselPageViewModel"/> class.
        /// </summary>
        public CarouselPageViewModel()
        {
            _pageTitle = "CarouselViewChallege";
            _animal = new ObservableCollection<AnimalModel>();
            _animal.Add(new AnimalModel { Title = "Cute dog", ImagePath = "https://th.bing.com/th/id/OIP.iRjeVJfvve4N0MfUky12HgHaEK?w=294&h=164&c=7&o=5&pid=1.7" });
            _animal.Add(new AnimalModel { Title = "Cute cat", ImagePath = "https://th.bing.com/th/id/OIP.__BpwPGRP9yjsUa8MaS5UQHaFj?w=217&h=163&c=7&o=5&pid=1.7" });
            _animal.Add(new AnimalModel { Title = "Whahaha", ImagePath = "https://th.bing.com/th/id/OIP.rKSQ8lmDeHwH29L73NFsUAHaFj?w=242&h=178&c=7&o=5&pid=1.7" });
        }

        /// <summary>
        /// Gets or sets the animals.
        /// </summary>
        /// <value>The animals.</value>
        public ObservableCollection<AnimalModel> Animals
        {
            get
            {
                return _animal;
            }
            set
            {
                if (_animal != value)
                {
                    _animal = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Birds"));
                }
            }
        }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>The title.</value>
        public string Title
        {
            get
            {
                return _pageTitle;
            }
            set
            {
                if (_pageTitle != value)
                {
                    _pageTitle = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Title"));
                }
            }
        }

        /// <summary>
        /// Handles the <see cref="E:PropertyChanged" /> event.
        /// </summary>
        /// <param name="eventArgs">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
        private void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
        {
            PropertyChanged?.Invoke(this, eventArgs);
        }
    }
}

Create a new MainPage.xaml under View.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="https://xamarin.com/schemas/2014/forms"
             xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="https://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="CarouselViewChallenge.Views.MainPage">
    <ContentPage.Content>
        <StackLayout>
            <CarouselView ItemsSource="{Binding Animals}" PeekAreaInsets="50">
                <CarouselView.ItemTemplate>
                    <DataTemplate>

                        <StackLayout>
                            <Frame BorderColor="Gray" Margin="8" HasShadow="True" HeightRequest="250" CornerRadius="20" VerticalOptions="CenterAndExpand">
                                <StackLayout>
                                    <Image Source="{Binding ImagePath}"/>
                                    <Label Text="{Binding Title}" FontSize="24" FontAttributes="Bold" HorizontalTextAlignment="Center"/>
                                </StackLayout>
                            </Frame>
                        </StackLayout>
                    </DataTemplate>
                </CarouselView.ItemTemplate>
            </CarouselView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

In the code behind bind the viewmodel with the page:

using CarouselViewChallenge.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace CarouselViewChallenge.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MainPage : ContentPage
    {
        CarouselPageViewModel vm;

        public MainPage()
        {
            InitializeComponent();

            vm = new CarouselPageViewModel();
            BindingContext = vm;
        }
    }
}

The project is working for Android, iOS and UWP. The source code is available on Github.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.