/ReactiveUI

An MVVM framework for .NET that integrates the Reactive Extensions (Rx) framework

Primary LanguageC#Microsoft Public LicenseMS-PL

ReactiveUI

This library is an exploration I've been working on for several weeks on combining WPF Model-View-ViewModel paradigm with the Reactive Extensions for .NET (Rx). Combining these two make managing concurrency as well as expressing complicated interactions between objects possible in a declarative, functional way. Put simply, if you've ever had to chain events / callbacks together and declare state ints/booleans to keep track of what's going on, Reactive Extensions provides a sane alternative.

What's in this library

ReactiveCommand - an implementation of ICommand that is also a Subject whose OnNext is raised when Execute is executed. Its CanExecute can also be defined by an IObservable which means the UI will instantly update instead of implementations which rely on RequerySuggested.

ReactiveAsyncCommand - a derivative of ReactiveCommand that encapsulates the common pattern of "Fire asynchronous command, then marshal result back onto dispatcher thread". Allows you to set a maximum level of concurrency as well (i.e. "I only want 3 inflight requests" - when the maximum is reached, CanExecute returns false).

ReactiveObject - a ViewModel object based on Josh Smith's implementation, that also implements IObservable as a way to notify property changes. It also allows a straightforward way to observe the changes of a single property.

ReactiveValidatedObject - a derivative of ReactiveObject that is validated via DataAnnotations by implementing IDataErrorInfo, so properties can be annotated with their restrictions and the UI will automatically reflect the errors.

ObservableAsPropertyHelper<T> - a class that easily lets you convert an IObservable into a property that stores its latest value, as well as fires NotifyPropertyChanged when the property changes. This is really useful for combining existing properties together and replacing IValueConverters, since your ViewModels will also be IObservables.

StopwatchTestScheduler - this class allows you to enforce time limits on items scheduled on other threads. The main use for this is in unit tests, as well as being able to say things in Debug mode like, "If any item runs in the Dispatcher scheduler for longer than 400ms that would've made the UI unresponsive, crash the application".

Blend SDK Integration

AsyncCommandVisualStateBehavior - this behavior will watch a ReactiveAsyncCommand and transition its target to different states based on the command's status - for example, displaying a Spinner while a command is running.

FollowObservableStateBehavior - this behavior will use the output of an IObservable and call VisualStateManager.GoToState on its target; using Observable.Merge makes it fairly straightforward to build a state machine based on the changes in the ViewModel.

ObservableTrigger - this trigger will fire when an IObservable calls OnNext and can be tied to any arbitrary Expression Action.

Other stuff that's useful

MemoizingMRUCache - this class is non-threadsafe most recently used cache, and can be used to cache the results of expensive lookups. You provide the function to use to look up values that aren't known, then it will save the results. It also allows a "destructor" to be run when an item is released from the cache, so you can use this to manage an on-disk file cache as well (where the "Get" function downloads a file, then the "Release" function deletes it).

QueuedAsyncMRUCache - this class is by far the most complicated in this library, its goals are similar to MemoizingMRUCache, but instead of returning the result immediately, it will schedule a Task to run in the background and return an IObservable representing the result (a Future). Once the Future completes, its result is cached so subsequent requests will come from memory.

The advantage of this class is that subsequent identical requests will block on the outstanding one (so if you ask for "foo.com" on 3 separate threads, one of them will send out the web request and the other two threads will receive the result as well). This class also allows you to place a blocking limit on the number of outstanding requests, so that further requests will block until some of the inflight requests have been satisfied.

IEnableLogger - this is an implementation of a simple logger that combines some of log4net's syntax with the ubiquity of the Rails logger - any class that implements the dummy IEnableLogger interface will able to access a logger for that class (i.e. this.Log().Warn("Something bad happened!");)