Using ReactiveUI for WinForms MVVM Design

http://www.codeproject.com/Articles/801986/Using-ReactiveUI-for-WinForms-MVVM-Design

https://www.nuget.org/packages/reactiveui-winforms/

 

 

A brief example showing how to use the Reactive UI framework to perform a separation of concerns using MVVM.

Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.

Introduction

In this article, we will look at an elegant way to separate the UI concerns of the presentation layer of a WinForms application from the application business logic using a MVVM (Model-View-ViewModel) pattern. In this way, Test-Driven-Development (TDD) of the application can be facilitated.

Background

While reading an article by Peter Vogel (see VSMagazine2014-05-01), I was reminded again of the difficulty WinForm application designers have working with modern design patterns. I have been searching for a long time for an easier way to accomplish what Brian Noyes appears to have accomplished with WinForms (see Composite Extensions for WinForms) without the contortions of using code borrowed from the Patterns and Practices Composite WPF Contrib library (http://compositewpfcontrib.codeplex.com/), which is difficult to follow and appears to have been abandoned (like so many things on the internet). However, the recent appearance ofReactiveUI 6.0 promises to improve the development of WinForms applications. ReactiveUI 6.0 is a Model-View-ViewModel framework that’s used along with the Reactive Extensions library in constructing testable UIs.

Using the code

Let’s go through a brief example of using ReactiveUI to construct a WinForms application that uses the MVVM pattern. I will be using Visual Studio 2013 Express for Windows Desktop and the default WinForms template. Open up the main form created by the template and add the following controls:

  • Text label
  • Text box
  • OK button
  • StatusStrip Status string

Use the NuGet Package Manager under the Tools menu and add the reactiveui-winforms package to the solution. This package will add all the necessary references and components we will need.

At this point, since the view is partially constucted, we  construct the ViewModel that will process data and events. Lets set up properties with backing fields for the controls on the view and one command for the button.

//
// ViewModel example
//
namespace WinFormMVVM.ViewModels
{
	public class HomeViewModel : ReactiveUI.ReactiveObject
	{
		string ModelString;
		public string EnteredText
		{
			get { return ModelString; }
			set { this.RaiseAndSetIfChanged( ref ModelString, value);}
		}

		string statusString = "";
		public string Status
		{
			get{return statusString;}
			set{this.RaiseAndSetIfChanged(ref statusString,value);}
		}

		public ReactiveCommand<object> OKCmd { get; private set; }

		public HomeViewModel
		{
			var OKCmdObs = this.WhenAny(vm => vm.EnteredText, 
				s => !string.IsNullOrWhiteSpace(s.Value));
			OKCmd = ReactiveCommand.Create(OKCmdObs);
			OKCmd.Subscribe(_=> Status = EnteredText + " is saved.");
		}
	}
}

The ViewModel inherits from the ReactiveObject class. This class  grants your classes access to theRaiseAndSetIfChanged helper function. This conveniently wires up your properties to the INotifyPropertyChanged/IObservable interfaces, so in one step you have a class that can be data bound AND observed using Reactive Extensions.

In the constructor for the ViewModel we set up the conditions under which something happens, i.e. when the OK button is clicked. An IObservable object is returned from the WhenAny extension, which allows you to observe whenever one or more properties on an object have changed. We then Subscribe to the events of theReactiveCommand, which will update the status message. Note that the ViewModel has no references to any UI elements, which allows us to perform testing without worrying about the particular UI technology used.

The astute reader will notice that at this point there is no link between the View and the ViewModel. Let’s take care of that now that the ViewModel is built. Edit the View to inherit from the interface IViewFor<T>, where T is our ViewModel.

namespace WinFormMVVM
{
	public partial class HomeView : Form, IViewFor<HomeViewModel>
	{
		InitializeComponent();
		VM = new HomeViewModel();

		// Bind the view to the ReactiveUI viewmodel
		this.Bind(VM, x => x.EnteredText, x => x.textBoxMyInput.Text);
		this.Bind(VM, x => x.Status, x => x.toolStripMyStatusString.Text);
		this.BindCommand(VM, x => x.OKCmd, x => x.btnOK);
	}

	public HomeViewModel VM { get; set; }

	object IViewFor.ViewModel
	{
		get { return VM; }
		set { VM = (HomeViewModel)value; }
	}

	HomeViewModel IViewFor<HomeViewModel>.ViewModel
	{
		get { return VM; }
		set { VM = value; }
	}
}

What I really like about using this framework is the availability of intellisense in writing the bindings between the UI elements and the VIewModel properties. The absence of “magic strings” typical in XAML or regular WinForm data bindings, that really makes code maintenance difficult, is especially welcome.

Points of Interest

The present state of the ReactiveUI framework is not documented as well as might be hoped for. It took a fair amount of time to ferret out meaning from outdated examples and code breaking changes. I hope this example will serve to inspire others to dig into ReactiveUI and provide more examples and better documentation.

History

2014-Jul-29 Initial Draft

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s