/ReactiveUI

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming. ReactiveUI allows you to abstract mutable state away from your user interfaces, express the idea around a feature in one readable place and improve the testability of your application.

Primary LanguageC#MIT LicenseMIT

NuGet Stats Build Status Code Coverage #yourfirstpr Dependabot Status



What is ReactiveUI?

ReactiveUI is a composable, cross-platform model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming which is a paradigm that allows you to abstract mutable state away from your user interfaces and express the idea around a feature in one readable place and improve the testability of your application.

πŸ”¨ Get Started πŸ› Install Packages 🎞 Watch Videos πŸŽ“ View Samples 🎀 Discuss ReactiveUI

Introduction to Reactive Programming

Long ago, when computer programming first came to be, machines had to be programmed quite manually. If the technician entered the correct sequence of machine codes in the correct order, then the resulting program behavior would satisfy the business requirements. Instead of telling a computer how to do its job, which error-prone and relies too heavily on the infallibility of the programmer, why don't we just tell it what it's job is and let it figure the rest out?

ReactiveUI is inspired by the paradigm of Functional Reactive Programming, which allows you to model user input as a function that changes over time. This is super cool because it allows you to abstract mutable state away from your user interfaces and express the idea around a feature in one readable place whilst improving application testability. Reactive programming can look scary and complex at first glance, but the best way to describe reactive programming is to think of a spreadsheet:

  • Three cells, A, B, and C.
  • C is defined as the sum of A and B.
  • Whenever A or B changes, C reacts to update itself.

That's reactive programming: changes propagate throughout a system automatically. Welcome to the peanut butter and jelly of programming paradigms. For further information please watch the this video from the Xamarin Evolve conference - Why You Should Be Building Better Mobile Apps with Reactive Programming by Michael Stonis.

NuGet Packages

Install the following packages to start building your own ReactiveUI app. Note: some of the platform-specific packages are required. This means your app won't perform as expected until you install the packages properly. See the Installation docs page for more info.

Platform ReactiveUI Package NuGet Events Package
.NET Standard ReactiveUI CoreBadge None
ReactiveUI.Fody FodyBadge None
Unit Testing ReactiveUI.Testing TestBadge None
Universal Windows ReactiveUI CoreBadge ReactiveUI.Events
WPF ReactiveUI.WPF WpfBadge ReactiveUI.Events.WPF
Windows Forms ReactiveUI.WinForms WinBadge ReactiveUI.Events.WinForms
Xamarin.Forms ReactiveUI.XamForms XamBadge ReactiveUI.Events.XamForms
Xamarin.Essentials ReactiveUI CoreBadge ReactiveUI.Events.XamEssentials
Xamarin.Android ReactiveUI.AndroidSupport DroBadge ReactiveUI.Events
Xamarin.iOS ReactiveUI CoreBadge ReactiveUI.Events
Xamarin.Mac ReactiveUI CoreBadge ReactiveUI.Events
Tizen ReactiveUI CoreBadge ReactiveUI.Events
Avalonia Avalonia.ReactiveUI AvaBadge None
Any ReactiveUI.Validation ValidationsBadge None

A Compelling Example

Let’s say you have a text field, and whenever the user types something into it, you want to make a network request which searches for that query.

public interface ISearchViewModel
{
    string SearchQuery { get; set; }	 
    ReactiveCommand<string, IEnumerable<SearchResult>> Search { get; }
    IEnumerable<SearchResult> SearchResults { get; }
}

Define under what conditions a network request will be made

We're describing here, in a declarative way, the conditions in which the Search command is enabled. Now our Command IsEnabled is perfectly efficient, because we're only updating the UI in the scenario when it should change.

var canSearch = this.WhenAnyValue(x => x.SearchQuery, query => !string.IsNullOrWhiteSpace(query));

Make the network connection

ReactiveCommand has built-in support for background operations and guarantees that this block will only run exactly once at a time, and that the CanExecute will auto-disable and that property IsExecuting will be set accordingly whilst it is running.

Search = ReactiveCommand.CreateFromTask(_ => searchService.Search(this.SearchQuery), canSearch);

Update the user interface

ReactiveCommands are themselves IObservables, whose values are the results from the async method, guaranteed to arrive on the UI thread. We're going to take the list of search results that the background operation loaded, and turn them into our SearchResults property declared as ObservableAsPropertyHelper<T>.

_searchResults = Search.ToProperty(this, x => x.SearchResults);

Handling failures

Any exception thrown from the ReactiveCommand.CreateFromTask gets piped to the ThrownExceptions Observable. Subscribing to this allows you to handle errors on the UI thread.

Search.ThrownExceptions.Subscribe(error => { /* Handle exceptions. */ });

Throttling network requests and automatic search execution behaviour

Whenever the Search query changes, we're going to wait for one second of "dead airtime", then automatically invoke the subscribe command.

this.WhenAnyValue(x => x.SearchQuery)
    .Throttle(TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler)
    .InvokeCommand(Search);

Binding our ViewModel to the platform-specific UI

ReactiveUI fully supports XAML markup bindings, but we have more to offer. ReactiveUI Bindings work on all platforms, including Xamarin Native and Windows Forms, and operate the same. Those bindings are strongly typed, and renaming a ViewModel property, or a control in the UI layout without updating the binding, the build will fail.

this.WhenActivated(cleanup => 
{
    this.Bind(ViewModel, x => x.SearchQuery, x => x.TextBox)
        .DisposeWith(cleanup);
    this.OneWayBind(ViewModel, x => x.SearchResults, x => x.ListView)
        .DisposeWith(cleanup);
    this.BindCommand(ViewModel, x => x.Search, x => x.Button)
        .DisposeWith(cleanup);
});

Forget about INotifyPropertyChanged boilerplate code

ReactiveUI.Fody package allows you to decorate read-write properties with Reactive attribute β€” and code responsible for property change notifications will get injected into your property setters automatically at compile time. We use Fody tooling to make this magic work.

public class ReactiveViewModel : ReactiveObject
{
    [Reactive] 
    public string SearchQuery { get; set; }
}

The code above gets compiled into the following code:

public class ReactiveViewModel : ReactiveObject
{
    private string searchQuery;
    public string SearchQuery 
    {
        get => searchQuery;
        set => this.RaiseAndSetIfChanged(ref searchQuery, value);
    }
}

Validate user input on the fly

ReactiveUI.Validation provides a subset of functions to create validations, functioning in a reactive way. For those ViewModels which need validation, implement ISupportsValidation, then add validation rules to the ViewModel and finally bind to the validation rules in the View! See documentation for more info. This package was created based on jcmm33 work and maintained by alexmartinezm.

// # ViewModel
// Search query must not be empty. The selector is the property 
// name and the line below is a single property validator.
this.ValidationRule(
    vm => vm.SearchQuery,
    query => !string.IsNullOrWhiteSpace(query),
    "Please, provide a non-empty search query!");

// # View
// Bind any validations which reference the SearchQuery property 
// to the text of the QueryValidation UI control!
this.BindValidation(ViewModel, vm => vm.SearchQuery, view => view.QueryValidation.Text);

Add view model-based routing to your XAML views

View model-based routing is supported for Xamarin.Forms, WinRT, UWP, Windows Forms, WPF and Avalonia Desktop applications. Create an IScreen, register views for view models and navigate to your IRoutableViewModels by calling Router.Navigate. Then, bind the RoutingState to the platform-specific routed view host. See routing documentation for a getting started guide.

<rxui:ReactiveWindow
    xmlns:rxui="http://reactiveui.net" 
    x:Class="ReactiveRouting.MainWindow"
    x:TypeArguments="vm:MainViewModel"
    xmlns:vm="clr-namespace:ReactiveRouting"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <rxui:RoutedViewHost
        Router="{Binding Router}"
        HorizontalContentAlignment="Stretch"
        VerticalContentAlignment="Stretch" />
</rxui:ReactiveWindow>

Support

If you have a question, please see if any discussions in our GitHub issues or Stack Overflow have already answered it.

If you want to discuss something or just need help, here is our Slack room where there are always individuals looking to help out!

If you are twitter savvy you can tweet #reactiveui with your question and someone should be able to reach out and help also.

If you have discovered a 🐜 or have a feature suggestion, feel free to create an issue on GitHub.

Contribute

ReactiveUI is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. Because of our Open Collective model for funding and transparency, we are able to funnel support and funds through to our contributors and community. We ❀ the people who are involved in this project, and we’d love to have you on board, especially if you are just getting started or have never contributed to open-source before.

So here's to you, lovely person who wants to join us β€” this is how you can support us:

We're also looking for people to assist with code reviews of ReactiveUI contributions. Please join us on Slack to discuss how.

.NET Foundation

ReactiveUI is part of the .NET Foundation. Other projects that are associated with the foundation include the Microsoft .NET Compiler Platform ("Roslyn") as well as the Microsoft ASP.NET family of projects, Microsoft .NET Core & Xamarin Forms.

Core Team


Geoffrey Huntley

Sydney, Australia


Kent Boogaart

Adelaide, Australia


Glenn Watson

Washington, USA


Rodney Littles II

Texas, USA


Artyom Gorchakov

Moscow, Russia


Colt Bauman

South Korea

Alumni Core Team

The following have been core team members in the past.


Olly Levett

London, United Kingdom


Paul Betts

San Francisco, USA


Brendan Forster

Melbourne, Australia


Oren Novotny

New York, USA

Contributors

This project exists thanks to all the people who have contributed to the code base.

Sponsorship

The core team members, ReactiveUI contributors and contributors in the ecosystem do this open source work in their free time. If you use ReactiveUI a serious task, and you'd like us to invest more time on it, please donate. This project increases your income/productivity too. It makes development and applications faster and it reduces the required bandwidth.

This is how we use the donations:

  • Allow the core team to work on ReactiveUI
  • Thank contributors if they invested a large amount of time in contributing
  • Support projects in the ecosystem that are of great value for users
  • Support projects that are voted most (work in progress)
  • Infrastructure cost
  • Fees for money handling

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site.

Backers

Become a backer and get your image on our README on Github with a link to your site.