What is lacking in the first version of the hello world example is the separation of UI and application logic. A refactored WinForms version may be the topic of a future post.
The next step in the discovery of Rx is to create a similar software using WPF. The details can be viewed in the source code, so let’s concentrate on the peculiarities. In this version, pure Rx will be used without ReactiveUI.
WPF brings a possibility of total separation of UI, UI logic and application logic. A part of the application can be implemented by bindings to a viewmodel. The viewmodel has to implement the INotifyPropertyChanged interface. We’ll choose the implementation from here for the moment.
The viewmodel is defined as follows, omitting the INotifyPropertyChanged details:
public class MyViewModel : INotifyPropertyChanged { //http://msdn.microsoft.com/en-us/library/ms229614.aspx details ... string _CurrentTime; public string CurrentTime { get { return _CurrentTime; } private set { if (value != _CurrentTime) { _CurrentTime = value; NotifyPropertyChanged(); } } } string _TextInput; public string TextInput { get { return _TextInput; } set { if (value != _TextInput) { _TextInput = value; NotifyPropertyChanged(); UpdateWordCount(); } } } private void UpdateWordCount() { WordCount = TextInput.Split() .DefaultIfEmpty() .Where(s => s.Trim().Length > 0) .Count(); } int _WordCount; public int WordCount { get { return _WordCount; } private set { if (value != _WordCount) { _WordCount = value; NotifyPropertyChanged(); } } } public MyViewModel() { Observable.Interval(TimeSpan.FromSeconds(1)) .Subscribe(_ => CurrentTime = DateTime.Now.ToLongTimeString()); } }
By using the separation the application logic becomes testable without building a UI, as the viewmodel is not dependent on System.Windows*.
The word count and the current time field can be bound to the controls by using the standard binding mechanism:
<TextBox ... Text="{Binding CurrentTime}"></TextBox> <TextBox ... Text="{Binding WordCount}"></TextBox>
However, if we want the word count to be updated on every text change and not after focus change, we’ll have to use the TextChanged of the third text box to update the viewmodel. The update of the word count is currently implemented in the setter for the TextInput property on line 29. Using ReactiveUI this will change as well.
The configuration of the UI by code-behind looks as follows:
ViewModels.MyViewModel VM = new ViewModels.MyViewModel(); DataContext = VM; var textChanged = Observable.FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>( handler => handler.Invoke, h => textBox3.TextChanged += h, h => textBox3.TextChanged -= h); textChanged.Subscribe(_ => VM.TextInput = textBox3.Text);
Compared to the first WinForms version it has two responsibilities less – the current time update logic and the word count logic, which is now in the viewmodel.
As the next step, the implementation of the viewmodel should be further simplified.
Source code can be found here.