Refreshing a ListView with ReactiveCommand

Introduction

In this article, we are going to learn how to bind a Xamarin.Form ListView to a ReactiveUI ReactiveCommand. This article extends the example from previous blog posts.

Setting Up

Let's get started by implementing a small service stub to provide dummy data that we'll later get from our content API.

As you can see below we've created a simple Get method which emulates a slow asynchronous operation by using the Task.Delay method. This is purely used for demonstration purposes and will allow us to demonstrate how an asynchronous ReactiveCommand is created and used.

public interface IArticleService
{
	Task<IEnumerable<Article>> Get();
}

public class ArticleService : IArticleService
{
	int _index = 1;

	public async Task<IEnumerable<Article>> Get()
	{
		await Task.Delay(2000);
		return new List<Article> { new Article { Title = $"Article {_index++}" }, new Article { Title = $"Article {_index++}" } };
	}
}

Defining a ReactiveCommand

The generic ReactiveCommand type takes two generic type parameters. The first parameter is used to determine what kind of input parameter we want to send to the command. The second parameter is used to determine the type our command will return.

By specifying Unit as the input parameter type, we are effectively saying that there is no input parameter for our command. You can also specify Unit as the output type as well which would mean that we are neither taking any input or providing any output.

For our command definition, we want to define a command that takes no input and returns an enumerable collection of Articles.

ReactiveList<string> _articles;
readonly IArticleService _articleService;

public ReactiveCommand<Unit, IEnumerable<Article>> LoadArticles { get; private set; }

public ReactiveList<string> Articles
{
	get => _articles;
	set => this.RaiseAndSetIfChanged(ref _articles, value);
}

Defining Our Command Logic

For our example we will define two methods. The first method represents the implementation of our command, and the second method is used to map the results of our command to our ViewModel.

async Task<IEnumerable<Article>> LoadArticlesImpl()
{
    return await _articleService.Get();
}

void MapArticlesImpl(IEnumerable<Article> articles)
{
    using (Articles.SuppressChangeNotifications())
    {
        Articles.Clear();
        articles.ToObservable().Subscribe(x => Articles.Add(x.Title));
    }
}

Composing our Command

We now need to instantiate our asynchronous command using the ReactiveCommand.CreateFromTask method. This method takes our LoadArticlesImpl method as a parameter, this parameter is used to specify what code should be run when our command is executed.

We then want to take the output of our command and process it using our MapArticlesImpl method. This is done by calling the Subscribe(MapArticlesImpl) method.

We use the ObserveOn(RxApp.MainThreadScheduler) method to ensure that our MapArticlesImpl code is executed on the main UI thread. This is important, as executing on a background thread may lead to the UI not updating as you would expect it to.

public ArticlesViewModel(IBlogService blogService)
{
    _articleService = new ArticleService();
    Articles = new ReactiveList<string>();

    LoadArticles = ReactiveCommand.CreateFromTask(LoadArticlesImpl);

   
 LoadArticles.ObserveOn(RxApp.MainThreadScheduler)
						.Subscribe(MapArticlesImpl);

			
    LoadArticles.Execute().Subscribe();
}

Binding ReactiveCommand to ListView Refresh Event

The final thing we need to do is wire up our ListView to our newly created ReactiveCommand.

Before we creating our binding, we need enable the PullToRefresh interaction with our ListView. This is done simply by setting the IsPullToRefreshEnabled property to true in our Xaml file.

<ListView x:Name="Articles" IsPullToRefreshEnabled="true"/>

Next we need to bind our ViewModel command to the Refreshing event on the ListView.

this.BindCommand(ViewModel, vm => vm.LoadArticles, v => v.Articles, nameof(ListView.Refreshing)).DisposeWith(_bindingsDisposable);

ViewModel.LoadArticles.Subscribe(_ => Articles.EndRefresh());

You'll see that we've also added a subscription to the LoadArticles command in order to notify the ListView that we have finished refreshing the data.

Summary

We should now have a ViewModel that allows a user to interact with it through a command that is bound to the pull to refresh interaction.

Full source code for this post can be found here:
https://github.com/jamilgeor/FormsTutor/tree/master/Lesson04

Note

You'll notice in the GitHub source, I have now upgraded nuget package for Xamarin.Forms to the latest pre-release version. This is to get around a known bug, that has since been resolved:
https://github.com/reactiveui/ReactiveUI/issues/806

References

ReactiveCommand design guidelines
https://docs.reactiveui.net/en/design-guidelines/commands.html