Tag Archives: refactoring

The WPF + ReactiveUI Refactored Version of the Responsive UI Hello World

Overview

To recapitulate, the first article in the series used Reactive Extensions (Rx) directly in Windows Forms UI logic to implement a UI with a simulated background calculation, which delivered a timestamp each second. The rest of the application was an input text box, for which, when the user inputs the text, the word count is calculated asynchronously and posted into another read-only text box.

The second article introduced a WPF version of the same UI with a viewmodel that implements the INotifyPropertyChanged interface and supplies the ticker text and the word count as bindable properties. The text being input was delivered to the viewmodel via an event converted to an observable sequence, which was used to update the TextInput property of the viewmodel. The WordCount was updated from the setter of TextInput.

The third article recreated the WPF implementation in WinForms using the same viewmodel, which is shared between the two projects. The third UI implementation introduced throttling of the TextInput changes to 0.3 seconds so that the word count is updated only when the user pauses for at least a third of a second to take a look at the result.

The Refactored WPF Version

In this article, the WPF UI is further refactored, so that the concerns are separated further. These are organized as follows:

Create a sequence of some calculation results

These are timestamps in this case, implemented as an object, providing an IObservable<string> property Ticker:

public class BackgroundTicker
{
    public IObservable<string> Ticker
    {
        get
        {
            return Observable
                .Interval(TimeSpan.FromSeconds(1))
                .Select(_ => DateTime.Now.ToLongTimeString());
        }
    }
}

The observable sequence is active, delivering a value every second.

Count words in text asynchronously and provide another property calculated in the background

This viewmodel is finally implemented using ReactiveUI:

public class WordCounterModel : ReactiveObject

The word count and the input text are ReactiveUI boilerplate:

string _TextInput;
public string TextInput
{
    get { return _TextInput; }
    set { this.RaiseAndSetIfChanged(ref _TextInput, value); }
}

ObservableAsPropertyHelper<int> _WordCount;
public int WordCount
{
    get { return _WordCount.Value; }
}

The value sequence of the background ticker is injected at construction time using its observable member. The word count and the background ticker properties are implemented using an ObservableAsPropertyHelper.
The results of the background ticker are exposed via a property:

ObservableAsPropertyHelper<string> _BackgroundTicker;
public string BackgroundTicker
{
    get { return _BackgroundTicker.Value; }
}

the helper is initialized from the constructor-supplied observable:

someBackgroundTicker
    .ToProperty(this, ticker => ticker.BackgroundTicker, out _BackgroundTicker);

And finally, the word count logic is implemented as an output property, transforming the sequence of strings into a sequence of integers:

this.WhenAnyValue(x => x.TextInput)
    .Where(x => !string.IsNullOrWhiteSpace(x))
    .Select(x => x
        .Split()
        .Where(word => !string.IsNullOrWhiteSpace(word))
        .Count())
    .ToProperty(this, vm => vm.WordCount, out _WordCount);

The throttling can be removed from the viewmodel, as the WPF 4.5 has a Delay binding property, which can be used for the same purpose on the view side, freeing the viewmodel from that concern.

Provide a Graphical UI

Now let’s look at the view. The event subscription is gone and data binding is implemented in XAML declaratively. The DataContext of the main window is initialized with an instance of the viewmodel, which is initialized with an observable from an instance of a background ticker:

ViewModels.BackgroundTicker Ticker=new ViewModels.BackgroundTicker();
ViewModels.WordCounterModel VM = new ViewModels.WordCounterModel(Ticker.Ticker);
DataContext = VM;

This instantiation can be definitely made in XAML as well, nullifying the amount of C# code for the view, as for example in the following article.

The background ticker and the word count are now bound one-way and marked asynchronous.

<TextBox ... Text="{Binding BackgroundTicker,IsAsync=True,Mode=OneWay}"></TextBox>
<TextBox ... Text="{Binding WordCount,IsAsync=True,Mode=OneWay}"></TextBox>

And finally, the binding of the input text is configured in XAML to be throttled to 300 milliseconds and bind on PropertyChanged events of the Text property of the text box:

<TextBox ... Text="{Binding TextInput, UpdateSourceTrigger=PropertyChanged, Delay=300}"></TextBox>

Source Code

https://github.com/d-led/reactiveexamples

First refactoring of the WinForms UI example

The hello world UI example started here is at first sight not optimal to demonstrate the positive effects of UI and app logic separation, since the amount of boilerplate code required to write the viewmodel without using a specialized framework is larger than the savings in the UI logic code. However, the testability of the viewmodel is granted having created the separation. The example also does not contain an explicitly defined model, apart from the “current” DateTime.

Windows Forms have bindings that understand the INotifyPropertyChanged interface, which we can recycle in the first refactoring of the WinForms example.

The complete project can be viewed on GitHub. As you will notice, the viewmodel is shared between this version and the first WPF one.

Only in the Form1_Load event handler of the form is tackled here.

The old code:

Observable.Interval(TimeSpan.FromSeconds(1))
    .ObserveOn(this)
    .Subscribe(x => textBox1.Text = DateTime.Now.ToLongTimeString());

var textChanged = Observable.FromEventPattern
    <EventHandler, EventArgs>(
    handler => handler.Invoke,
    h => textBox3.TextChanged+= h,
    h => textBox3.TextChanged-= h);

textChanged
    .ObserveOn(this) // scheduled on the Form's scheduler
    .Subscribe(x => textBox2.Text =
        textBox3.Text
        .Split()
        .DefaultIfEmpty()
        .Where(s=>s.Trim().Length>0)
        .Count()
        .ToString());

and the new one:

ViewModels.MyViewModel VM = new ViewModels.MyViewModel();

textBox1.DataBindings.Add("Text", VM, "CurrentTime");
textBox2.DataBindings.Add("Text", VM, "WordCount");

var textChanged = Observable.FromEventPattern
    <EventHandler, EventArgs>(
    handler => handler.Invoke,
    h => textBox3.TextChanged += h,
    h => textBox3.TextChanged -= h);

textChanged
    .Throttle(TimeSpan.FromSeconds(0.3))
    .ObserveOn(this)
    .Subscribe(_ => VM.TextInput = textBox3.Text);
[1. for a more MVVM approach, see a newer article]

Still the TextChanged event is used for the update of the viewmodel. The relevant changes are highlighted and are similar to the first WPF version. As you can see, the code is extremely similar to the WPF version.

The updated version instantiates the viewmodel, creates the bindings and subscribes the update of the viewmodel’s text. As a slight responsiveness improvement over the first two versions, the observable TextChanged events are throttled to 0.3 seconds with the idea that the word count is of no interest to the user during typing.

When the application becomes more elaborate, it’s expected that the savings become substantial, especially when using a specialized MVVM framework, such as ReactiveUI. At this stage, there is still no lifetime control of the observable’s subscriptions.

The next step is to start using ReactiveUI for the viewmodel.