Oki Dokie… Let’s try out our Xamarin Forms AwesomeListView…

Hope you guy’s recall my previous post on Xamarin Forms Custom Listview with some added awesomeness… 😉 Where I unveiled a listview that is actually awesome ? 😀 Well as promised here is the article about the sample application I will be developing using my AwesomeListView.

Now for this article we will create a small Xamarin Forms app, which is going to load a bunch of dummy contacts to a listview… 😀

Let’s begin…

So this is how it’s all gonna stack up,

capture

As you can see above you need to create a Xamarin Forms project solution. And within that I have separated the code based on MVVM pattern, whereas we will be using the ObservableObject class as the base for handling properychanged and command events. Contacts Page shall be our View which we are gonna fit in our awesome-listview 😉 !

And yes hereby I’m gonna call it AwesomeListView ! 😀

Setting up the Data Source…

First create a Modal class called Contacts. This shall be the modal class for our Contacts items for the listview.

namespace WhateverYourNamespace.Models
{
    public class Contact
    {
        public String Name{ get; set; }
        public String Phone { get; set; }
    }
}

 

Now we need to create a tiny repository class, which will return a bunch of dummy data to be populated in out listview. Well don’t worry ! obviously I wasn’t going to hardcode that by myself, I’m a engineer for my degree certificate’s sake 😛 lol

So we are going to be using this tiny awesome library to generate our dummy data, Faker.Net.Portable ! Surprisingly enough its a pretty cool library which can populate real-like dummy data with ease. You can read all about it on my blog post about it, https://theconfuzedsourcecode.wordpress.com/2015/11/07/wanna-create-an-awesome-dummy-data-set/

Anyways go ahead and add that library to your project from Nuget Package Manager, to your PCL, Xam.Android, Xam.iOS and Xam.WinPhone…

With that now we can set up our data source repository as follows.

namespace WhateverYourNamespace.DataAccess
{
    public class ContactsRepository
	{
        public static List<Contact> FakeContactsList = new List<Contact>();

        public ContactsRepository() 
        {
            for (int i = 0; i < 100; i++)
            {
                try
                {
                    // Generating dummy data and adding to the list 

                    var name = Faker.Name.FullName();
                    var phone = Faker.Phone.CellNumber();

                    FakeContactsList.Add(new Contact { Name = name, Phone = phone });
                }
                catch (Exception)
                {

                }
            }
        }
    }
}

 

In our ContactsRepository class we are going to be having a List items source with a static reference, and in the runtime we will populate our fake data in the constructor and add them to the static list.. Pretty straight forward ! 😀

Setting up the ViewModel…

Now we need to set up our ViewModel classes for the Listview to be used, therefore we shall begin by creating the base ObservableObject class which is going to be an abstract with the INotifyPropertyChanged handlers.

namespace WhateverYourNamespace.Core
{
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public virtual event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 

Now let’s dive into our ViewModel, whereas we shall be creating the ContactsPageViewModel which is to be used with the Awesome-Listview of ours. 😉 Now just for the case of article, I will provide you with section by section of the whole ViewModel as shown below… So if you are already writing the code while reading this article, I suggest you keep including the code snippets which will be given in this article, step by step just as it is.. 😉

Constructor and Private Values for the ViewModel

Below is the constructor and the private values to  be used in our ViewModel…

namespace WhateverYourNamespace.ViewModels
{
    class ContactsPageViewModel : ObservableObject
    {
        private readonly INavigation _navigation;
        private List<Contact> _repository;
        private ObservableCollection<Contact> _contactsList;
        private bool _isBusy;
        private bool _isFree;
        private bool _isLoadMoreEnabled;
        private bool _isDataListEmpty;
        private string _filterBy;
        private int _loadedCount;
        private Contact _selectedContact;

        public ContactsPageViewModel(List<Contact> repository, INavigation navigation)
        {
            LoadMoreContactsCommand = new Command(LoadMoreContacts);

            _repository = repository;
            _navigation = navigation;
            _loadedCount = 0;
            _filterBy = "FILTER1";
            IsBusy = false;
            _isDataListEmpty = false;
            _isLoadMoreEnabled = true;

            LoadMoreContacts();
        }
		
	// Properties Section //
		
	// Commands Section //
		
	// Methods Section //
     }
}

 

As you can see, we shall be passing in a List of Contacts as the Item Repository, which is to be used for providing data for each loading cycle of the list view. I have also instantiated a Command property there in the constructor, which shall be explained in the coming paragraphs of this article. And as for the rest of Private variables and their default values, you will get the idea in the next section…

// Properties // for the ViewModel

Below are the Properties which should be included in the above ViewModel class (right underneath the Constructor would be idea 😉 )

#region Properties

/// <summary>
/// Gets or Sets the ContactsList value
/// </summary>
public ObservableCollection<Contact> ContactsList
{
	get { return _contactsList ?? (_contactsList = new ObservableCollection<Contact>()); }
}

/// <summary>
/// Gets or Sets the Filter String value, used for filtering the loaded results...
/// </summary>
public string FilterBy
{
	get { return _filterBy; }
	set
	{
		_filterBy = value;
		FilterAndReLoadContacts();
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets the currently loaded items count
/// </summary>
public int LoadedCount
{
	get { return _loadedCount; }
	set
	{
		_loadedCount = value;
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets the Selected Contact Item in the list
/// </summary>
public Contact SelectedContact
{
	get { return _selectedContact; }
	set
	{
		_selectedContact = value;
		GoToContactDisplayPage();
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets the IsBusy value, used for disabling any UI Control while loading data...
/// </summary>
public bool IsBusy
{
	get { return _isBusy; }
	set
	{
		_isBusy = value;
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets the IsFree value, used for re-enabling any UI Control after loading data (opposite of IsBusy) ...
/// </summary>
public bool IsFree
{
	get { return _isFree; }
	set
	{
		_isFree = value;
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets IsLoadMoreEnabled value, used for disabling Load More button when no results available
/// </summary>
public bool IsLoadMoreEnabled
{
	get { return _isLoadMoreEnabled; }
	set
	{
		_isLoadMoreEnabled = value;
		OnPropertyChanged();
	}
}

/// <summary>
/// Gets or Sets the IsDataListEmpty value, used For displaying empty result set.
/// </summary>
public bool IsDataListEmpty
{
	get { return _isDataListEmpty; }
	set
	{
		_isDataListEmpty = value;
		OnPropertyChanged();
	}
}

#endregion

 

Those are the properties as said, and I have given a small description for each property and its use, so I hope I wouldn’t have to give much of an explanation here… 🙂 I hope those above properties may solve the mystery regarding the private methods used in the Constructor.

// Commands // for the ViewModel

Below is the command that we will be implementing in the ViewModel.

#region Commands

public ICommand LoadMoreContactsCommand { get; set; }

#endregion

 

Hope you remember we instantiated a command in the Constructor of our ViewModel, yes this is the command we are using there.

If you are done including the Commands let’s move into the Methods implementation.

// Methods // for the ViewModel

Below are the set of methods which should be included in the ViewModel.

#region Methods

private async void LoadMoreContacts()
{
	if (IsBusy)
	{
		return;
	}

	IsBusy = true;
	IsFree = false;

	try
	{
		await Task.Delay(2000);

		// Check if the data source is empty 
		if (_repository.Count == 0)
		{
			IsDataListEmpty = true;
			IsLoadMoreEnabled = false;

			IsBusy = false;
			IsFree = true;

			return;
		}

		// Check if all the items in the source are loaded to UI
		if (ContactsList.Count == _repository.Count)
		{
			IsLoadMoreEnabled = false;

			IsBusy = false;
			IsFree = true;

			return;
		}


		int LoadBeginIndex = 0;
		int LoadEndIndex = 10;

		// Setting the Begin Index for 2nd hit and forward
		if (ContactsList.Count != 0)
		{
			LoadBeginIndex = ContactsList.Count;
		}

		// Check if the Current Loading Rage is with in the data set size
		if (LoadEndIndex > (_repository.Count - ContactsList.Count))
		{
			LoadEndIndex = (_repository.Count - ContactsList.Count);
		}

		// Loading the selected data set to the UI
		var characters = _repository.GetRange(LoadBeginIndex, LoadEndIndex);
		foreach (var character in characters)
		{
			ContactsList.Add(character);
		}

		LoadedCount = ContactsList.Count;
	}
	catch (Exception ex)
	{

	}

	IsBusy = false;
	IsFree = true;
}

private async void FilterAndReLoadContacts()
{
	if (IsBusy)
	{
		return;
	}

	IsBusy = true;
	IsFree = false;

	try
	{
		// Include your Filtering algorithm ...

		// You could filter the ContactsList in 
		// any order you wish and reset it back to it
	}
	catch (Exception ex)
	{

	}

	IsBusy = false;
	IsFree = true;
}

private async void GoToContactDisplayPage()
{
	if (SelectedContact == null)
		return;

	//Code to navigate the user to any other new Page to view details of the selected item
}

#endregion 

 

Now as you can see above, LoadMoreContacts() is used for loading the next set of results from the Repository object and setting to the ListView. There you can see we are using IsBusy and IsFree properties which is to notify the interface that the background processing is happening, which you could use to wire up to some UI controllers and use them as you wish. 🙂 Also you may have noticed the Await Timers inside the method, well that was just to simulate the waiting of the data loading, just for this sample app.

Then I have included the FilterAndReLoadContacts() method just as a skeleton method for you to implement your  own Filtering mechanism.

GoToContactDisplayPage() method will be used to pop up the detailed view of the selected item, which will be called through the SelectedContact property value change.

That’s all for the ViewModel for our Awesome-ListView, next make sure you have set up my AwesomeList in your project…

Setting up the AwesomeListView …

Well if you haven’t yet set up my AwesomeListView, then you better head into my previous article and do that right now and come back to this article to continue. https://theconfuzedsourcecode.wordpress.com/2015/11/10/xamarin-forms-custom-listview-with-some-added-awesomeness/

Alright ! if that’s set up then let’s dive into the MVVM’s “View” code…

Setting up the View …

So we need to set up the View for our MVVM implementation right ? I suggest we create a small ContentPage and include our AwesomeListView in it and do the necessary bindings with the above ViewModel…

Go ahead and create ContactsPage view in your Views folder as follows.

namespace WhateverYourNamespace.Views
{
    class ContactsPage : ContentPage
    {
        ContactsPageViewModel _viewModel;

        AwesomeListView ListView_Contacts = new AwesomeListView(true);

        public ContactsPage()
        {
	    // Defining UI Controls and setting up Bindings
            
            this.Appearing += ContactsPage_Appearing;
        }

        private void ContactsPage_Appearing(object sender, EventArgs e)
        {
            if (ListView_Contacts.ItemsSource == null)
            {
                // Populating the data in Repository
                ContactsRepository repo = new ContactsRepository();

                // Creating the ViewModel with necessary parameters
                _viewModel = new ContactsPageViewModel(ContactsRepository.FakeContactsList, this.Navigation);

                // Setting the created ViewModel to this View
                this.BindingContext = _viewModel;
            }
        }
    }
}

 

Yes we need to create an instance of the ContactsPageViewModel and also an instance of our AwesomeListView. There you can see I’m passing in ‘true’ value to the contructor, which means I’m going to be using the ListView with a ‘Load More’ footer button. 😀

I recommend that inside the Page.Appearing method only we should be setting up our BindingContext as we can make sure that all the UI Controls are loaded, whereas you can see there in the ContactsPage_Appearing() method I’m creating the Datasource – ContactsRepository and passing it into the ViewModel’s constructor. Thereby ending the execution with setting the BindingContext to it.

Nope we are not done yet, we need to Initialization the UI controls inside the Constructor right ? including our AwesomeListView as follow… So replace the above Constructor with the following code snippet.

public ContactsPage()
{
	var ListItemTemplate = new DataTemplate(typeof(TextCell));
	ListItemTemplate.SetBinding(TextCell.TextProperty, "Name");
	ListItemTemplate.SetBinding(TextCell.DetailProperty, "Phone");

	ListView_Contacts.SetBinding(AwesomeListView.ItemsSourceProperty, "ContactsList");
	ListView_Contacts.SetBinding(AwesomeListView.SelectedItemProperty, "SelectedContact");
	ListView_Contacts.SetBinding(AwesomeListView.IsEnabledProperty, "IsFree");
	ListView_Contacts.SetBinding(AwesomeListView.IsBusyProperty, "IsBusy");
	ListView_Contacts.SetBinding(AwesomeListView.IsLoadMoreItemsPossibleProperty, "IsLoadMoreEnabled");
	ListView_Contacts.ItemTemplate = ListItemTemplate;

	ListView_Contacts.SetBinding(AwesomeListView.LoadMoreItemsFooterCommandProperty, "LoadMoreContactsCommand");

	Label lbl_ContactsEmptyAlert = new Label()
	{
		Text = "Sorry ! Contacts list is currently empty... Please check back later...",
		HorizontalOptions = LayoutOptions.CenterAndExpand,
		VerticalOptions = LayoutOptions.CenterAndExpand,
		FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
		XAlign = TextAlignment.Center
	};
	lbl_ContactsEmptyAlert.SetBinding(Label.IsVisibleProperty, "IsDataListEmpty");
	StackLayout StackLayout_ContactsEmptyAlert = new StackLayout
	{
		Children = { lbl_ContactsEmptyAlert },
		Padding = new Thickness(10, 0, 10, 5),
	};
	StackLayout_ContactsEmptyAlert.SetBinding(StackLayout.IsVisibleProperty, "IsDataListEmpty");
	
	Label lbl_LoadedCount = new Label()
	{
		FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
	};
	lbl_LoadedCount.SetBinding(Label.TextProperty, "LoadedCount", BindingMode.TwoWay, null, "Loaded {0} items ...");

	if (Device.OS != TargetPlatform.WinPhone)
	{
		this.Padding = new Thickness(5, Device.OnPlatform(5, 0, 0), 5, 5);
	}

	this.Content = new StackLayout
	{
		Children = 
		{
			StackLayout_ContactsEmptyAlert,
			new StackLayout
			{
				Children = 
				{ 
					lbl_LoadedCount
				},
				Padding = new Thickness(10, 0, 0, 0),
			},
			ListView_Contacts
		}
	};

	this.Appearing += ContactsPage_Appearing;
}

 

First we will be creating a small DataTemplate of TextCell, then we shall be initializing our AwesomeListView with the necessary bindings. As you can see above I have set up all the Bindable Properties of our AwesomeListView to the ViewModel’s properties and commands. ItemsSourceProperty, SelectedItemProperty, IsEnabledProperty are quite ordinary properties of a generic ListView, then you can see our custom properties being binded such as, IsBusyProperty, IsLoadMoreItemsPossibleProperty, LoadMoreItemsFooterCommandProperty which are the extra features provided by our AwesomeListView.

The lbl_ContactsEmptyAlert is a label that will show up when the Datasource is empty, based on the IsDataListEmpty property of the ViewModel. I have created a small Label lbl_LoadedCount to show how many items have been loaded to the ListView which also binded to the ViewModel’s LoadedCount property.

Now that should set up everything perfectly, let’s fire it up then…

Finally let’s FIRE IT UP… ! 😉

If you had implemented everything properly, there should be no compilation errors, therefore just hit 5 and watch the magic… 😀

// Here we go…

2

// While loading the data to ListView…

1

// After it reaches the end of the Data source…

3

// When the Data source is empty…

4

Some Wisdom…

Now after everything worked out beautifully, it’s all up to your how you are going to use this and improve it to display in your own App’s… 😉 Just a matter of your Imagination !

As I have mentioned I left the Filtering code blank for you to write your own algorithm, but if you find it hard, here is just a tip, set up a couple of buttons in the View and have them set the value of FilterBy in the ViewModel, where as in the Set event, we are calling the filtering method right ? there catch the certain string value and do the filtering based on that for the ContactsList in the ViewModel.

Inside the LoadMoreContacts() method you could even call a webservice of your choice and have a tiny pagination algorithm set up so you could load the data set by set…

Like I said it’s all just a matter of your Imagination ! 😉

Well there it goes folks, hope this post was helpful for you and prolly saved you some time… 🙂 Please share this among other developers as this may become handy for another developer as well, and you may save their precious time as well…

Cheers folks ! Stay Awesome ! 😀

 

Advertisements

3 thoughts on “Oki Dokie… Let’s try out our Xamarin Forms AwesomeListView…

  1. Great article.
    I followed it to the letter.
    But I always get the error:
    Error CS1061 ‘AwesomeListView’ does not contain a definition for ‘Footer’ and no extension method ‘Footer’ accepting a first argument of type ‘AwesomeListView’ could be found (are you missing a using directive or an assembly reference?
    at the line this.Footer = new StackLayout {…} in the AwasomeListView Class

  2. No man…
    It is not that…
    I have everything up-to-date.
    And I still get the following error:
    CS1061 ‘AwesomeListView’ does not contain a definition for ‘Footer’ and no extension method ‘Footer’ accepting a first argument of type ‘AwesomeListView’ could be found (are you missing a using directive or an assembly reference?) AwsmListContactsPortable C:\Users\Oussama\Documents\Visual Studio 2015\Projects\AwsmListContactsPortable\AwsmListContactsPortable\AwsmListContactsPortable\Controls\AwesomeListView.cs 53 Active

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s