This is a sample app that shows how to use System.Reactive
and ReactiveUI
with Terminal.Gui
. The app uses the MVVM architecture that may seem familiar to folks coming from WPF, Xamarin Forms, UWP, Avalonia, or Windows Forms. In this app, we implement the data bindings using ReactiveUI WhenAnyValue
syntax and ObservableEvents — a Source Generator that turns events into observable wrappers.
In order to use reactive extensions scheduling, copy-paste the TerminalScheduler.cs
file into your project, and add the following lines to the composition root of your Terminal.Gui
application:
Application.Init ();
RxApp.MainThreadScheduler = TerminalScheduler.Default;
RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
Application.Run (new RootView (new RootViewModel ()));
From now on, you can use .ObserveOn(RxApp.MainThreadScheduler)
to return to the main loop from a background thread. This is useful when you have a IObservable<TValue>
updated from a background thread, and you wish to update the UI with TValue
s received from that observable.
If you wish to implement OneWay
data binding, then use the WhenAnyValue
ReactiveUI extension method that listens to INotifyPropertyChanged
events of the specified property, and converts that events into IObservable<TProperty>
:
// 'usernameInput' is 'TextField'
ViewModel
.WhenAnyValue (x => x.Username)
.BindTo (usernameInput, x => x.Text);
Note that your view model should implement INotifyPropertyChanged
or inherit from a ReactiveObject
. If you wish to implement OneWayToSource
data binding, then install Pharmacist.MSBuild into your project and listen to e.g. TextChanged
event of a TextField
:
// 'usernameInput' is 'TextField'
usernameInput
.Events () // The Events() extension is generated by Pharmacist.
.TextChanged
.Select (old => usernameInput.Text)
.DistinctUntilChanged ()
.BindTo (ViewModel, x => x.Username);
If you combine OneWay
and OneWayToSource
data bindings, you get TwoWay
data binding. Also be sure to use the string
type instead of the string
type. Invoking commands should be as simple as this:
// 'clearButton' is 'Button'
clearButton
.Events ()
.Clicked
.InvokeCommand (ViewModel, x => x.Clear);