A collection of links and snippets to resources, samples, answers, people, videos, etc. related to ReactiveUI.
Most of these are pretty dated but still have a lot of relevance.
A lot of these are taken from this thread, but I find it easier to browse when it's organized by platform, like this.
WorkoutWotch - Xamarin Forms Video Series - The accompanying video series, referenced in the README, covers Xamarin iOS Native, but the codebase was later converted to Xamarin Forms to support other platforms.
Reactive Examples by TheEightBot
XamarinEvolve2014 - Heavily commented demo app by Ani Betts
Burger ingredient streams demo with blog post
WorkoutWotch - Xamarin Forms Video Series - The accompanying video series, referenced in the README, covers Xamarin iOS Native, but the codebase was later converted to Xamarin Forms to support other platforms.
ReactiveTableView & ReactiveCollectionView Demo
Sample code for the book "You, I, and ReactiveUI"
Book: You, I, and ReactiveUI - Love this book. Highly recommended.
Reactive Extensions for .NET Developers with Michael Stonis (November 2018)
Why You Should Be Building Better Mobile Apps with Reactive Programming – Michael Stonis
public SuspensionHost(ISuspensionDriver driver = null)
{
driver = driver ?? Locator.Current.GetService<ISuspensionDriver>();
}
Explanation: This uses a Service Located interface for the default interface, but only if the caller didn't give an explicit one in the constructor. Far more straightforward to test in a unit test runner than trying to construct a sham IoC container, but still falls back to a default implementation at runtime.
Source: https://stackoverflow.com/a/26924067/5984310
this.WhenAnyValue(x => x.ViewModel.LoadItems)
.SelectMany(x => x.ExecuteAsync())
.Subscribe();
Explanation: Invoking async operations in the ViewModel constructor means that your ViewModel class becomes more difficult to test, because you always have to mock out the effects of calling LoadItems, even if the thing you are testing is unrelated.
Source: https://codereview.stackexchange.com/a/74793
- No need
public MyViewModel()
{
MyReactiveCommand
.Execute()
.Subscribe(...);
}
Quote by Kent Boogart (one of the ReactiveUI maintainers):
When the execution of a ReactiveCommand completes, all observers are auto-unsubscribed anyway. Generally, subscriptions to pipelines that have a finite lifetime (eg. via a timeout) need not be disposed manually. Disposing of such a subscription is about as useful as disposing of a MemoryStream.
- Do dispose
public MyView()
{
this.WhenAnyValue(x => x.ViewModel)
.Do(PopulateFromViewModel)
.Subscribe();
}
This one is tricky. Disposing of this subscription is a must if developing for a dependency property-based platform such as WPF or UWP. Quoting Ani Betts, this is because "there's no non-leaky way to observe a dependency property," which is exactly what the ViewModel property of a ReactiveUserControl is. However, if you happen to know that your ViewModel won't change for the liftime of the view then you can make ViewModel a normal property, eliminating the need to dispose. For other platforms such as Xamarin.Forms, Xamarin.Android, and Xamarin.iOS there's no need to dispose because you're simply monitoring the property (ViewModel) on the view itself, so the subscription is attaching to PropertyChanged on that view. This means the view has a reference to itself and thus, doesn't prevent the it from being garbage collected.
- Do dispose
public MyViewModel()
{
SomeService.SomePipeline
.Subscribe(...);
}
Services commonly have a longer lifetime than view models, especially in the case of singletons and global application variables. Therefore, it's vital that these kinds of subscriptions are disposed of.
- No need
public MyViewModel()
{
SomeService.SomePipelineModelingAsynchrony
.Subscribe(...);
}
Pipelines modeling asynchrony can be relied upon to complete, and thus the subscription will be disposed of automatically via OnComplete (or OnError).
- Do dispose
public MyView()
{
this.WhenAnyValue(x => x.ViewModel.SomeProperty)
.Do(AssignValueToViewControl)
.Subscribe();
}
Now you're saying "attach to PropertyChanged on this and tell me when the ViewModel property changes, then attach to PropertyChanged on that (the view model) and tell me when SomeProperty changes." This implies the view model has a reference back to the view, which needs to be cleaned up or else the view model will keep the view alive.
- Performance tip
public MyView()
{
// For a dependency property-based platform such as WPF and UWP
this.WhenActivated(
disposables =>
{
this.WhenAnyValue(x => x.ViewModel)
.Where(x => x != null)
.Do(PopulateFromViewModel)
.Subscribe()
.DisposeWith(disposables);
});
// For other platforms it can be simplified to the following
this.WhenAnyValue(x => x.ViewModel)
.Where(x => x != null)
.Do(PopulateFromViewModel)
.Subscribe()
}
private void PopulateFromViewModel(MyViewModel vm)
{
// Assign values from vm to controls
}
More efficient than binding to properties. If your ViewModel properties don't change over time, definitely use this pattern. The WhenActivated part is important for dependency property-based platforms (as mentioned in case 2) since it will handle disposing of the subscription every time the view is deactivated.
- No need
// Should I dispose of the IDisposable that WhenActivated returns?
this.WhenActivated(
disposables =>
{
...
})
Quote by Kent Boogart:
If you're using WhenActivated in a view, when do you dispose of the disposable that it returns? You'd have to store it in a local field and make the view disposable. But then who disposes of the view? You'd need platform hooks to know when an appropriate time to dispose it is - not a trivial matter if that view is reused in virtualization scenarios. In addition to this, I have found that reactive code in VMs in particular tends to juggle a lot of disposables. Storing all those disposables away and attempting disposal tends to clutter the code and force the VM itself to be disposable, further confusing matters. Perf is another factor to consider, particularly on Android.
Ani Betts @anaisbetts
- Github
- Book: Programming Reactive Extensions and LINQ
- Stack Overflow - System.Reactive
- Stack Overflow - ReactiveUI
Kent Boogaart @kent_boogaart
Stack Overflow Top Users for ReactiveUI
WhenActivated
WhenActivated: allows you to specify the things that should occur when a view or view model is activated and deactivated; requries that our view implements IActivatable; Typically, you don't need to worry about disposing of the disposable returned by WhenActivated. Views tend to deactivate naturally as a consequence of users navigating through your application and ReactiveUI's default IActivationForViewFetcher implementations.
IActivatable: think of it as IActivatableView; implemented by IViewFor; tag interface (no methods to implement)
ISupportsActivation: think of it as IActivatableViewModel; requires that the IViewFor invokes WhenActivated; can test view model activation and deactivation by calling Activate and Deactivate; implementing this interface more than once in a view model class hierarchy will result in view model activation failing to work correctly
ViewModelActivator: essentially a sink in which WhenActivated will register the blocks of activation logic provided by your view model
IActivationForViewFetcher: implements GetAffinityForView and GetActivationForView
GetAffinityForView: method of IActivationForViewFetcher; tells ReactiveUI how confident you are that your implementation of IActivationForViewFetcher can provide activation information for a given view; higher numbers returned by this method trump lower numbers returned by other implementations
GetActivationForView: method of IActivationForViewFetcher; returns IObservable that ticks true when the view is activated and false when the view is deactivated
NAVIGATION
RoutingState: NavigationStack, Navigate (ReactiveCommand), NavigateBack (ReactiveCommand), NavigateAndReset (ReactiveCommand)
IScreen: Router (RoutingState); root of a navigation stack; despite the name, its views don't have to occupy the whole screen
IRoutableViewModel: UrlPathSegment (string), HostScreen (IScreen)
RoutedViewHost: platform-specific; monitors an instance of RoutingState, responding to any changes in the navigation stack by creating and embedding the appropriate view