mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Remove NStack and replace ustring to string.
* Add unit test and improving some code.
* Adjust code and fix all unit tests errors.
* Add XML Document and move the Rune folder into the Text folder.
* Improve unit tests with byte array on DecodeRune and DecodeLastRune.
* Fix unit test.
* 😂Code review
* Reduce unit tests code.
* Change StringExtensions.Make to StringExtensions.ToString and added some more unit tests.
* Fix merge errors.
* Remove GetTextWidth and calls replaced with StringExtensions.GetColumns.
* Hack to use UseSystemConsole passed in the command line arguments.
* Revert "Hack to use UseSystemConsole passed in the command line arguments."
This reverts commit b74d11c786.
* Remove Application.UseSystemConsole from the config file.
* Fix errors related by removing UseSystemConsole from the config file.
* Fixes #2633. DecodeEscSeq throw an exception if cki is null.
* Fix an exception if SelectedItem is -1.
* Set SelectedItem to 0 and remove unnecessary ToString.
* Using a unique ToString method for Rune and other for byte.
* Fix a bug where a wider rune is added with only a width of 1.
* Force the SelectedGlyph is the one that was typed after jumpList is executed.
* Added more InlineData to RuneTests.
* Reducing significantly the code by using Theory attribute in the TextFormatterTests.
* Override PositionCursor to handle the CharMap cursor position.
* Fix merge errors.
* Minor tweaks to API docs
---------
Co-authored-by: Tig Kindel <tig@users.noreply.github.com>
48 lines
2.5 KiB
Markdown
48 lines
2.5 KiB
Markdown
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 [Pharmacist](https://github.com/reactiveui/pharmacist) — a tool that converts all events in a NuGet package into observable wrappers.
|
|
|
|
<img src="https://user-images.githubusercontent.com/6759207/94748621-646a7280-038a-11eb-8ea0-34629dc799b3.gif" width="450">
|
|
|
|
### Scheduling
|
|
|
|
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:
|
|
|
|
```cs
|
|
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.
|
|
|
|
### Data Bindings
|
|
|
|
If you wish to implement `OneWay` data binding, then use the `WhenAnyValue` [ReactiveUI extension method](https://www.reactiveui.net/docs/handbook/when-any/) that listens to `INotifyPropertyChanged` events of the specified property, and converts that events into `IObservable<TProperty>`:
|
|
|
|
```cs
|
|
// '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](https://github.com/reactiveui/pharmacist) into your project and listen to e.g. `TextChanged` event of a `TextField`:
|
|
|
|
```cs
|
|
// '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:
|
|
```cs
|
|
// 'clearButton' is 'Button'
|
|
clearButton
|
|
.Events ()
|
|
.Clicked
|
|
.InvokeCommand (ViewModel, x => x.Clear);
|
|
``` |