Thursday Night

Paul Betts’s personal website / blog / what-have-you

ReactiveUI 4.0 Preview 2 is here

After coding some pretty interesting new features, as well as to update to the latest released version of Rx (2.01), I am now releasing a preview release of ReactiveUI 4.0. You can get the binaries one of two ways:

  • install-package reactiveui -pre or install-package reactiveui-winrt -pre
  • Download the Zip release from GitHub

How does this break backwards compatibility?

A few types have been renamed from 3.x (IViewForViewModel => IViewFor), a few deprecated methods have been removed (CollectionExtensions), and the biggest one is that NLog is now optional – if you want to use it, make sure to install the reactiveui-nlog package (it comes by default in the reactiveui metapackage)

WhenAny now works with any object!

WhenAny and ObservableForProperty now work with any .NET object. The runtime will detect what kind of object it is (DependencyObject, INPC, etc) and will determine how to get notifications from it. Note that if you use WhenAny with an object that doesn’t notify (like a regular .NET object), it will warn you on the logger that changes won’t be reported. This framework is extensible as well, so on MonoMac for example, notifications for NSObjects will be derived using Key-Value Observing (KVO).

This means that the old ObservableForDP method is now deprecated – use WhenAny instead.

View Bindings: A Compelling Replacement for XAML bindings

There are currently two methods that are used in the XAML world for binding Views to ViewModels. The original method, XAML Bindings (i.e. {Binding Foo}), is quite flexible, but a frustrating aspect of it is that Bindings that are incorrect, due to typos or other mistakes, don’t generate errors – you only see the error in the trace output. The Binding syntax can also get quite verbose, and isn’t always easy to verify because paths are relative to the “nearest” DataContext set.

Caliburn Micro decided to take a different approach, with their “Convention-Based Wireup” – this approach decides to automatically wire up named controls with the properties of the same name (even being smart enough to realize that the most “common” property of TextBox is the Text property). While this approach is much more “wrist friendly”, it suffers from the same type of run-time failures: CM cannot know whether a binding should exist or not.

ReactiveUI is presenting a new approach: wiring up controls via a declarative syntax. This has a number of advantages:

  • It’s still wrist-friendly
  • Bindings are clearly described in one place
  • Bindings that are never valid (i.e. because the property name has changed)
    break the build.
  • This binding syntax isn’t tied to Xaml – you can effectively use ReactiveUI
    bindings with any UI framework with a bit of work, including Cocoa (MonoMac)
    and GTK#.

Consider the following ViewModel, which is valid RxUI 3.x code as well:

public class MainPageViewModel : ReactiveObject
 {
 string _SomeText = "";
 public string SomeText {
 get { return _SomeText; }
 set { this.RaiseAndSetIfChanged(x => x.SomeText, value); }
 }

  ObservableAsPropertyHelper<string> _FooMirror;
  public string FooMirror {
      get { return _FooMirror.Value; }
  }

  public ReactiveCommand Ok { get; protected set; }

  public MainPageViewModel()
  {
      this.WhenAny(x => x.SomeText, x => x.Value)
          .Select(x => "Foo" + x ?? "")
          .ToProperty(this, x => x.FooMirror);

      Ok = new ReactiveCommand();
  }

}

In ReactiveUI 4.0, this is the way to wire up the View:

public partial class MainPage : Page, IViewFor<mainpageviewmodel>
 {
 public MainPage()
 {
 ViewModel = new MainPageViewModel();
 this.InitializeComponent();</mainpageviewmodel>

      // Connect the ViewModel's SomeText to the View's SomeText.Text
      this.Bind(ViewModel, x => x.SomeText, x => x.SomeText.Text);

      // Since the View half isn't specified here, it will default to the
      // control with the same name, and use the most "reasonable"
      // property, just like Caliburn Micro
      this.OneWayBind(ViewModel, x => x.FooMirror);

      // Ditto with Commands, find a Control named "Ok"
      this.BindCommand(ViewModel, x => x.Ok);
  }

  object IViewFor.ViewModel {
      get { return ViewModel; }
      set { ViewModel = (MainPageViewModel) value; }
  }
  public MainPageViewModel ViewModel { get; set; }

}

This feature is a work in progress, and there are definitely some cases that need to be smoothed out. However, I’d love feedback on whether this is useful or not.

Written by Paul Betts

August 27th, 2012 at 4:11 am

Posted in Uncategorized