×

iFour Logo

Xamarin Forms - ReactiveUi ToDo List

Kapil Panchal - July 21, 2021

Listening is fun too.

Straighten your back and cherish with coffee - PLAY !

  • play
  • pause
  • pause
Xamarin Forms - ReactiveUi ToDo List

What is ReactiveUi?


It is an advanced, Functional reactive MVVM and composable framework for all .Net frameworks.

ReactiveUi supports reactive programming to ease the implementation of the MVVM patterns in the application.

MVVM frame- Compared to other works, ReactiveUi is not very dictatorial.

Reactive UI

Here, the Reactive Extensions (Rx) library is an appropriate use which, we declare callbacks and can manage asynchronous executions in the code and using the LinQ syntax, it does all these tasks.

It removes the unstructured & difficultly manageable code and makes it readable.

Generating ToDo List using ReactiveUi


For starting the project, we need to install 3 packages in the PCL project using NuGet package.

  • ReactiveUi.XamForms package

  • DynamicData package

  • Sextant.XamForms package

And we’ll have to use the 8.0 or above version of C#.

Now, we have to create four folders as Managers, Models, ViewModels, and Views and add the appropriate file as mentioned below.

HomePage -> HomeViewModel handles the Todo List as it’s the home page.

ItemPage -> ItemVewModel adds and edits the single items.

The Item model represents the Todo item.

ItemManagers handles the collection of Todo.

Code for All added files:

IItemManager.cs

                public class ItemManager : IItemManager
{
    public ItemManager()
    {
      ItemChanges = _itemsCache.Connect().RefCount();
    }
    public Optional Get(string id) => _itemsCache.Lookup(id);
    public IObservable> ItemChanges { get; }
    public void AddOrUpdate(Item item) => _itemsCache.AddOrUpdate(item);
    public void Remove(Item item) => _itemsCache.Remove(item);
    private SourceCache _itemsCache = new SourceCache(item => item.Id);
}

              

Item.cs

                public class Item : ReactiveObject
{
  public Item(string id, string title)
  {
     Id = id;
     Title = title;
  }
  public string Id { get; }
  public string Title { get; }
  public bool IsCompleted
  {
    get => _isCompleted;
    set => this.RaiseAndSetIfChanged(ref _isCompleted, value);
  }
  private bool _isCompleted;
}
              

HomeViewModel.cs

                public class HomeViewModel : ViewModelBase
{
   public HomeViewModel(IParameterViewStackService navigationService, IItemManager 
    itemManager) : base(navigationService)
   {
     DeleteCommand = ReactiveCommand.Create(itemManager.Remove);
     itemManager
       .ItemChanges
       .Bind(out _items)
       .DisposeMany()
       .Subscribe()
       .DisposeWith(Subscriptions);            
    AddCommand = ReactiveCommand.CreateFromObservable(() => 
      NavigationService.PushModal());
    ViewCommand = ReactiveCommand.CreateFromObservable((item) =>
    {
      SelectedItem = null;
      return NavigationService.PushModal(new NavigationParameter()
      {
         { NavigationParameterConstants.ItemId , item.Id }
      });
    });
    this.WhenAnyValue(x => x.SelectedItem)
      .Where(x => x != null)
      .InvokeCommand(ViewCommand)
      .DisposeWith(Subscriptions);
  }
  public ReactiveCommand AddCommand { get; }
  public ReactiveCommand ViewCommand { get; }
  public ReactiveCommand DeleteCommand { get; }
  public Item SelectedItem
  {
     get => _selectedItem;
     set => this.RaiseAndSetIfChanged(ref _selectedItem, value);
  }
  public ReadOnlyObservableCollection Items => _items;
  public override string Id => "Reactive ToDo";
  private readonly ReadOnlyObservableCollection _items;
  private Item _selectedItem;
}

              

ItemViewModel.cs

  public class ItemViewModel:ViewModelBase
{
  public ItemViewModel(IParameterViewStackService navigationService, IItemManager 
   itemManager) : base(navigationService)
  {
    _itemManager = itemManager;
var canExecute = this.WhenAnyValue(x => x.Title, (title) => 
        !string.IsNullOrEmpty(title));
       SaveCommand = ReactiveCommand.Create(ExecuteSave, canExecute);
    
   CloseCommand = ReactiveCommand.CreateFromObservable(() =>     
     NavigationService.PopModal());
   SaveCommand
     .InvokeCommand(CloseCommand)
     .DisposeWith(Subscriptions);
   this.WhenAnyValue(x => x.ItemId)
      .Where(x => x != null)
      .Select(x => _itemManager.Get(x))
      .Where(x => x.HasValue)
      .Select(x => x.Value)
      .Subscribe(x =>
       {
           Title = x.Title;
       })
       .DisposeWith(Subscriptions);
  }
  public override IObservable WhenNavigatingTo(INavigationParameter parameter)
  {
     if (parameter.TryGetValue(NavigationParameterConstants.ItemId, out string itemId))
     {
       ItemId = itemId;
     }
     return base.WhenNavigatedTo(parameter);
  }
  private void ExecuteSave() => _itemManager.AddOrUpdate(new Item(ItemId ??    
   Guid.NewGuid().ToString(), Title));
  public ReactiveCommand SaveCommand { get; }
  public ReactiveCommand CloseCommand { get; }
  public override string Id => string.Empty;
  public string Title
  {
     get => _title;
     set => this.RaiseAndSetIfChanged(ref _title, value);
  }
  private string ItemId
  {
    get => _itemId;
       set => this.RaiseAndSetIfChanged(ref _itemId, value);
  }
  private string _title;
  private string _description;
  private readonly IItemManager _itemManager;
  private string _itemId;
}

ViewModelBase.cs

  public abstract class ViewModelBase:ReactiveObject,IDisposable,INavigable
{
   protected ViewModelBase(IParameterViewStackService viewStackService) =>  
     NavigationService = viewStackService;
   public abstract string id { get; }
   public virtual IObservable WhenNavigatedFrom(INavigationParameter parameter) =>      
     Observable.Return(Unit.Default);
   public virtual IObservable WhenNavigatedTo(INavigationParameter parameter) =>  
     Observable.Return(Unit.Default);
   public virtual IObservable WhenNavigatingTo(INavigationParameter parameter) =>  
     Observable.Return(Unit.Default);
  protected IParameterViewStackService NavigationService { get; }
  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
  protected virtual void Dispose(bool disposing)
  {
    if (disposing)
    {
      Subscriptions?.Dispose();
    }
  }
  protected readonly CompositeDisposable Subscription = new CompositeDisposable();
}

HomePage.xaml




            
            
            
            
            
            
            
            
            
            
            
                            
                        
            
            
                           
            
                        

ItemPage.xaml


App.xaml:

              
 

App.xaml.cs

 
            
    

NavigationParameterConstants.cs
            
RxExceptionHandler.cs
            

 

Add Item

 

 

Items List

 

 

List after deleting item

 

Conclusion


Using ReactiveUi, we get the power to make reactive, testable, and composable Ui as we use the MVVM pattern. The Todo list is used to manage our day-to-day timetable to be followed. And using this, we can also make some applications that give responses quickly and in an understandable way.

Xamarin Forms - ReactiveUi ToDo List Table of Content 1. What is ReactiveUi? 2. Generating ToDo List using ReactiveUi 3. Conclusion What is ReactiveUi? It is an advanced, Functional reactive MVVM and composable framework for all .Net frameworks. ReactiveUi supports reactive programming to ease the implementation of the MVVM patterns in the application. MVVM frame- Compared to other works, ReactiveUi is not very dictatorial. Here, the Reactive Extensions (Rx) library is an appropriate use which, we declare callbacks and can manage asynchronous executions in the code and using the LinQ syntax, it does all these tasks. It removes the unstructured & difficultly manageable code and makes it readable. Generating ToDo List using ReactiveUi For starting the project, we need to install 3 packages in the PCL project using NuGet package. ReactiveUi.XamForms package DynamicData package Sextant.XamForms package And we’ll have to use the 8.0 or above version of C#. Now, we have to create four folders as Managers, Models, ViewModels, and Views and add the appropriate file as mentioned below. HomePage -> HomeViewModel handles the Todo List as it’s the home page. ItemPage -> ItemVewModel adds and edits the single items. The Item model represents the Todo item. ItemManagers handles the collection of Todo. Code for All added files: IItemManager.cs public class ItemManager : IItemManager { public ItemManager() { ItemChanges = _itemsCache.Connect().RefCount(); } public Optional Get(string id) => _itemsCache.Lookup(id); public IObservable> ItemChanges { get; } public void AddOrUpdate(Item item) => _itemsCache.AddOrUpdate(item); public void Remove(Item item) => _itemsCache.Remove(item); private SourceCache _itemsCache = new SourceCache(item => item.Id); } Item.cs public class Item : ReactiveObject { public Item(string id, string title) { Id = id; Title = title; } public string Id { get; } public string Title { get; } public bool IsCompleted { get => _isCompleted; set => this.RaiseAndSetIfChanged(ref _isCompleted, value); } private bool _isCompleted; } HomeViewModel.cs public class HomeViewModel : ViewModelBase { public HomeViewModel(IParameterViewStackService navigationService, IItemManager itemManager) : base(navigationService) { DeleteCommand = ReactiveCommand.Create(itemManager.Remove); itemManager .ItemChanges .Bind(out _items) .DisposeMany() .Subscribe() .DisposeWith(Subscriptions); AddCommand = ReactiveCommand.CreateFromObservable(() => NavigationService.PushModal()); ViewCommand = ReactiveCommand.CreateFromObservable((item) => { SelectedItem = null; return NavigationService.PushModal(new NavigationParameter() { { NavigationParameterConstants.ItemId , item.Id } }); }); this.WhenAnyValue(x => x.SelectedItem) .Where(x => x != null) .InvokeCommand(ViewCommand) .DisposeWith(Subscriptions); } public ReactiveCommand AddCommand { get; } public ReactiveCommand ViewCommand { get; } public ReactiveCommand DeleteCommand { get; } public Item SelectedItem { get => _selectedItem; set => this.RaiseAndSetIfChanged(ref _selectedItem, value); } public ReadOnlyObservableCollection Items => _items; public override string Id => "Reactive ToDo"; private readonly ReadOnlyObservableCollection _items; private Item _selectedItem; } Read More: Exposure Notification Api Support For Xamarin Apps ItemViewModel.cs public class ItemViewModel:ViewModelBase { public ItemViewModel(IParameterViewStackService navigationService, IItemManager itemManager) : base(navigationService) { _itemManager = itemManager; var canExecute = this.WhenAnyValue(x => x.Title, (title) => !string.IsNullOrEmpty(title)); SaveCommand = ReactiveCommand.Create(ExecuteSave, canExecute); CloseCommand = ReactiveCommand.CreateFromObservable(() => NavigationService.PopModal()); SaveCommand .InvokeCommand(CloseCommand) .DisposeWith(Subscriptions); this.WhenAnyValue(x => x.ItemId) .Where(x => x != null) .Select(x => _itemManager.Get(x)) .Where(x => x.HasValue) .Select(x => x.Value) .Subscribe(x => { Title = x.Title; }) .DisposeWith(Subscriptions); } public override IObservable WhenNavigatingTo(INavigationParameter parameter) { if (parameter.TryGetValue(NavigationParameterConstants.ItemId, out string itemId)) { ItemId = itemId; } return base.WhenNavigatedTo(parameter); } private void ExecuteSave() => _itemManager.AddOrUpdate(new Item(ItemId ?? Guid.NewGuid().ToString(), Title)); public ReactiveCommand SaveCommand { get; } public ReactiveCommand CloseCommand { get; } public override string Id => string.Empty; public string Title { get => _title; set => this.RaiseAndSetIfChanged(ref _title, value); } private string ItemId { get => _itemId; set => this.RaiseAndSetIfChanged(ref _itemId, value); } private string _title; private string _description; private readonly IItemManager _itemManager; private string _itemId; } ViewModelBase.cs public abstract class ViewModelBase:ReactiveObject,IDisposable,INavigable { protected ViewModelBase(IParameterViewStackService viewStackService) => NavigationService = viewStackService; public abstract string id { get; } public virtual IObservable WhenNavigatedFrom(INavigationParameter parameter) => Observable.Return(Unit.Default); public virtual IObservable WhenNavigatedTo(INavigationParameter parameter) => Observable.Return(Unit.Default); public virtual IObservable WhenNavigatingTo(INavigationParameter parameter) => Observable.Return(Unit.Default); protected IParameterViewStackService NavigationService { get; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { Subscriptions?.Dispose(); } } protected readonly CompositeDisposable Subscription = new CompositeDisposable(); } HomePage.xaml ItemPage.xaml Planning to Hire Xamarin App Development Company ? LET'S DISCUSS App.xaml:   App.xaml.cs   public partial class App : Application { public App() { InitializeComponent(); RxApp.DefaultExceptionHandler = new RxExceptionHandler(); Instance.InitializeForms(); Locator .CurrentMutable .RegisterConstant(new ItemManager()); Locator .CurrentMutable .RegisterNavigationView(() => new NavigationView(RxApp.MainThreadScheduler, RxApp.TaskpoolScheduler, ViewLocator.Current)) .RegisterParameterViewStackService() .RegisterView() .RegisterView() .RegisterViewModel(() => new HomeViewModel(Locator.Current.GetService(), Locator.Current.GetService())) .RegisterViewModel(() => new ItemViewModel(Locator.Current.GetService(), Locator.Current.GetService())); Locator .Current .GetService() .PushPage(null, true, false) .Subscribe(); MainPage = Locator.Current.GetNavigationView("NavigationView"); } } NavigationParameterConstants.cs public class NavigationParameterConstants { public const string ItemId = "ItemId"; } RxExceptionHandler.cs public class RxExceptionHandler : IObserver { public void OnNext(Exception ex) { if (Debugger.IsAttached) { Debugger.Break(); } RxApp.MainThreadScheduler.Schedule(() => { throw ex; }); } public void OnError(Exception ex) { if (Debugger.IsAttached) { Debugger.Break(); } RxApp.MainThreadScheduler.Schedule(() => { throw ex; }); } public void OnCompleted() { if (Debugger.IsAttached) { Debugger.Break(); } RxApp.MainThreadScheduler.Schedule(() => { throw new NotImplementedException(); }); } }   Add Item     Items List     List after deleting item   Conclusion Using ReactiveUi, we get the power to make reactive, testable, and composable Ui as we use the MVVM pattern. The Todo list is used to manage our day-to-day timetable to be followed. And using this, we can also make some applications that give responses quickly and in an understandable way.
Kapil Panchal

Kapil Panchal

A passionate Technical writer and an SEO freak working as a Content Development Manager at iFour Technolab, USA. With extensive experience in IT, Services, and Product sectors, I relish writing about technology and love sharing exceptional insights on various platforms. I believe in constant learning and am passionate about being better every day.

Build Your Agile Team

Enter your e-mail address Please enter valid e-mail

Categories

Ensure your sustainable growth with our team

Talk to our experts
Sustainable
Sustainable
 
Blog Our insights
10 Executive Dashboard Examples for Consultants and CEOs
10 Executive Dashboard Examples for Consultants and CEOs

There is a principle behind every business. “If you don’t keep track of essentials, you won’t get clear direction, eventually causing your company to stumble.” To manage this scenario,...

How Spatial Data Analysis Improves Healthcare
How Spatial Data Analysis Improves Healthcare

Do you know when geospatial analysis took traction in healthcare? It was when John Snow, a London-based physician, used it to analyze the spread of cholera, which ultimately proved...

4 Types of Power BI Dashboards: Analytical, Strategic, Operational, and Tactical
4 Types of Power BI Dashboards: Analytical, Strategic, Operational, and Tactical

One interesting aspect you truly love about Power BI, as a CTO, is how it lets you step back and see the bigger picture of your business. Isn’t it? Without getting bogged down in minute...