Knockout Style Observables in XAML

402 views
Skip to first unread message

Daniel Vaughan

unread,
Jul 15, 2012, 5:34:08 PM7/15/12
to XAML Disciples
A couple of days ago, buried in this post
https://groups.google.com/group/wpf-disciples/browse_thread/thread/7326e0db31bebac8,
there was a brief discussion about field level data bindings. I wanted
to explore the idea further, and today I had a crack at prototyping
Knockout like observables and computed observables in WPF.
You can read more about it here http://danielvaughan.org/post/Knockout-Style-Observables-in-XAML.aspx
What I like most about today’s effort is the ComputedValue class. You
can specify a Lambda expression, which is traversed by the
ComputeValue class. Any INPC implementors are identified and
subscribed to. The class unsubscribes from INPC events when it is
disposed.
The following viewmodel excerpt shows how a composite property is
constructed from two non-composite properties:

class MainWindowViewModel
{
readonly ObservableValue<string> firstName = new
ObservableValue<string>("Alan");

public ObservableValue<string> FirstName
{
get
{
return firstName;
}
}

readonly ObservableValue<string> lastName = new
ObservableValue<string>("Turing");

public ObservableValue<string> LastName
{
get
{
return lastName;
}
}

readonly ComputedValue<string> fullName;

public ComputedValue<string> FullName
{
get
{
return fullName;
}
}

public MainWindowViewModel()
{
fullName = new ComputedValue<string>(() => FirstName.Value + " " +
ToUpper(LastName.Value));
}

string ToUpper(string s)
{
return s.ToUpper();
}
}

I think it’s an interesting approach, and goes some way to solving the
usual pain points associated with traditional INPC implementations in
XAML applications.

Cheers,
Daniel

Sachs Barber

unread,
Jul 15, 2012, 5:51:58 PM7/15/12
to wpf-di...@googlegroups.com, XAML Disciples
Kind if reminds me of my own chained property observer and philips lamda binding work.

Still good stuff

Sent from my iPhone

Daniel Vaughan

unread,
Jul 16, 2012, 3:30:45 AM7/16/12
to wpf-di...@googlegroups.com
Thanks mate.

On Sunday, July 15, 2012 11:51:58 PM UTC+2, Sacha Barber wrote:
Kind if reminds me of my own chained property observer and philips lamda binding work.

Still good stuff

Sent from my iPhone

Bill Kempf

unread,
Jul 16, 2012, 1:55:10 PM7/16/12
to wpf-di...@googlegroups.com
Nice article. I've been playing around with INPC stuff (again) recently and would like to point out a few things. First, data binding in WPF/SL/WinRT already has field level notification capabilities. We just usually forget about it.
 
private string name;
public event EventHandler FirstNameChanged;
public string Name
{
   get { return this.name; }
   set
   {
      if (this.name != value)
      {
         this.name = value;
         this.FirstNameChanged(this, EventArgs.Emtpy); // Not done "correctly", illustration only
      }
   }
}
 
This has worked in .NET for data binding and related scenarios since long before WPF, and WPF continues to support it.
 
As for computed values, Rx can really give you a lot of control here. Here's a fun little example.
 
    public static class BehaviorSubjectExtensions
    {
        public static void RaisePropertyChanged<TValue>(this IObservable<TValue> self, Expression<Func<TValue>> propertyExpression, Action<string> onPropertyChanged)
        {
            var f = (propertyExpression as LambdaExpression).Body as MemberExpression;
            if (f == null)
            {
                throw new ArgumentException("Only use expressions that call a single property.", "propertyExpression");
            }
            self.Subscribe(_ => onPropertyChanged(f.Member.Name));
        }
    }
 
    public class Person : INotifyPropertyChanged
    {
        private readonly BehaviorSubject<string> firstName = new BehaviorSubject<string>(string.Empty);
        private readonly BehaviorSubject<string> lastName = new BehaviorSubject<string>(string.Empty);
        private readonly IObservable<string> fullName;
 
        public Person()
        {
            this.firstName.RaisePropertyChanged(() => this.FirstName, this.OnPropertyChanged);
            this.lastName.RaisePropertyChanged(() => this.LastName, this.OnPropertyChanged);
            this.fullName = firstName.CombineLatest(lastName, (first, last) => string.Format("{0} {1}", first, last));
            this.fullName.RaisePropertyChanged(() => this.FullName, this.OnPropertyChanged);
        }
 
        public string FirstName
        {
            get { return this.firstName.First(); }
            set { this.firstName.OnNext(value); }
        }
 
        public string LastName
        {
            get { return this.lastName.First(); }
            set { this.lastName.OnNext(value); }
        }
 
        public string FullName
        {
            get { return this.fullName.First(); }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
I chose to use INPC in this example, but I could have gone with the observable property pattern instead. Rx gives you a lot more power in how you create computed values, allowing you to change the value based on more than just other properties that expose change notifications. For example, a snippet from ReactiveUI documentation.
 
DoubleTheString = new ReactiveAsyncCommand(null, 1 /* at a time */);
 
IObservable<string> doubled_strings = DoubleTheString.RegisterAsyncFunc(x => {
   // Pretend to be a slow function
   Thread.Sleep(1000);
   return string.Format("{0}{0}", x);
}
 
// ReactiveAsyncCommand will fire its OnNext when the command is *invoked*,
// and doubled_strings will fire when the command *completes* - let's use
// this to our advantage:
 
IObservable<string> result_or_loading = Observable.Merge(
   DoubleTheString.Select(x => "Loading..."),
   doubled_strings
);
 
Here, one of the computed values is "Loading..." and this value is computed based on the invocation of an ICommand not on some other property value.
 
What would be very nice is if WPF could handle field level property change notifications as IObservable<T> instead of an event.
 
private BehaviorSubject<string> firstName = new BehaviorSubject<string>(string.Empty);
 
public IObservable<string> FirstNameChanged
{
   get { return this.firstName.AsObservable(); }
}
 
public string FirstName
{
   get { return this.firstName.FirstOrDefault(); }
   set { this.firstName.OnNext(value); }
}
 
This certainly doesn't make the code any nicer. There's still a lot of boilerplate repetition involved. However things are now really Rx friendly and you can do some pretty powerful composing of events.
--
 Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.

Colin Eberhardt

unread,
Jul 16, 2012, 2:09:23 PM7/16/12
to Bill Kempf, wpf-di...@googlegroups.com
Some great food for thought, thanks Bill. Why haven't I heard of field-level notification before?!

Sent from my Windows Phone

From: Bill Kempf
Sent: 16/07/2012 18:55
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Knockout Style Observables in XAML

Bill Kempf

unread,
Jul 16, 2012, 2:11:00 PM7/16/12
to Colin Eberhardt, wpf-di...@googlegroups.com
Just a guess:
 
1. We didn't really call it field level notification.
2. We prefered INPC because it was less work!

Peter O'Hanlon

unread,
Jul 16, 2012, 2:31:15 PM7/16/12
to wpf-di...@googlegroups.com
I've gone with the Rx approach myself although it's not been anywhere near as sophisticated as this Bill. Nice one.



Colin Eberhardt

unread,
Jul 16, 2012, 2:42:25 PM7/16/12
to Bill Kempf, wpf-di...@googlegroups.com
I guess it one of those things, like change notification for classes that do not support INPC, that is a little obscure and certainly not mainstream.

Still, I'm surprised I hadn't heard of it before.

You also reminded me that I really need to use Rx properly one day. I just haven't worked on a project where it makes sense yet.


Sent from my Windows Phone

From: Bill Kempf
Sent: 16/07/2012 19:11
To: Colin Eberhardt
Cc: wpf-di...@googlegroups.com

Subject: Re: [WPF Disciples] Knockout Style Observables in XAML

Just a guess:
 
1. We didn't really call it field level notification.
2. We prefered INPC because it was less work!

On Mon, Jul 16, 2012 at 2:09 PM, Colin Eberhardt <colin.e...@gmail.com> wrote:
Some great food for thought, thanks Bill. Why haven't I heard of field-level notification before?!

Sent from my Windows Phone

Sachs Barber

unread,
Jul 16, 2012, 2:59:05 PM7/16/12
to wpf-di...@googlegroups.com
I don't think they exist Colin...it's clever but just a bit too clever. It's one of those things people will look at in years to come and go "yeah total rewrite sorry"

Sent from my iPhone

Bill Kempf

unread,
Jul 16, 2012, 3:16:05 PM7/16/12
to wpf-di...@googlegroups.com
Yeah, I don't know about that. I go back and forth on Rx. There's no doubt I dislike the naming in this library (Qbservable anyone?), and the code is often hard to understand at a glance, or at all for noobs. However, the declarative approach to event sequencing is undeniably powerful. There's lots of examples of things that are simple in Rx but are a PITA without it. Even the boring example of drag/drop event handling in Rx is far easier to code and more likely to be correct than traditional mechanisms. Basically, Rx makes it possible to use declarative programming to describe/implement a state machine.
 
We're using Rx pretty heavily at work. In fact, I think too heavily. A few devs fell in love and Rx is their new shiny hammer and every problem looks like a nail to them, even if it's a screw. There's no denying that this has caused several of our devs no end of pain, as they struggle to understand Rx and our code that uses it. However, when used appropriately, I really do think Rx is a great tool to have in your box. The code I illustrated from ReactiveUI I think is a good example. Achieving the same results in an imperative manner would have required a lot more code, and I think would be less understandable and far more likely to contain errors, especially as the code matures and is modified by multiple devs.

Daniel Vaughan

unread,
Jul 16, 2012, 3:23:13 PM7/16/12
to Peter O'Hanlon, wpf-di...@googlegroups.com
Thanks for the reminder about field level notification Bill. It awoke a long lost memory.
I'm going to look into this Rx approach.
Cheers, Daniel

Sent from my Windows Phone

From: Peter O'Hanlon
Sent: 16/07/2012 20:32
To: wpf-di...@googlegroups.com
Subject: RE: [WPF Disciples] Knockout Style Observables in XAML

I've gone with the Rx approach myself although it's not been anywhere near as sophisticated as this Bill. Nice one.



Colin E.

unread,
Jul 16, 2012, 3:56:41 PM7/16/12
to wpf-di...@googlegroups.com
On Mon, Jul 16, 2012 at 8:16 PM, Bill Kempf <wek...@gmail.com> wrote:
> Yeah, I don't know about that. I go back and forth on Rx. There's no doubt I
> dislike the naming in this library (Qbservable anyone?), and the code is
> often hard to understand at a glance, or at all for noobs.

From the time I spent playing with it, I was very impressed. The
classic drag and drop examples are quite enticing. However, I couldn't
see much use for Rx for many of your more common UI tasks.

However, what I really did like about it was that it made coordinating
calls to the service layer much more elegant and readable. I just lovd
creating 'pipelines' of calls that 'mash up' various services:

Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(30))
.SelectMany(ticks => searchTwitter("%23uksnow", _lastTweetId))
.Select(searchResult => ParseTwitterSearch(searchResult))
.ObserveOnDispatcher()
.Do(tweet => AddTweets(tweet))
.Do(tweets => UpdateLastTweetId(tweets))
.SelectMany(tweets => tweets)
.SelectMany(tweet => ParseTweetToUKSnow(tweet))
.SelectMany(snowTweet => searchBing(snowTweet))
.ObserveOnDispatcher()
.Subscribe(geoTweet => AddSnow(geoTweet));

Without Rx, the above is a mess of events and state flags.

However, I never did get round to looking into how exception handling
interrupts the above flow.

--
Regards,
Colin E.

Bill Kempf

unread,
Jul 16, 2012, 4:04:04 PM7/16/12
to wpf-di...@googlegroups.com
Check out ReactiveUI (http://www.reactiveui.net/). There's lots of compelling examples of using Rx for "common UI tasks". On the one hand I agree that it's not at first obvious, but once you see how much of your UI logic is really just a state machine and how Rx is perfect for controlling state machines...
 
That said, we've not used Rx much in the UI side of our code, so other than saying what I've seen intrigues me, I was/am in your camp on this one. I'm only just now starting to explore how Rx can work in real world UI work.
 
I'm also in full agreement that the error handling here is complex. I like how async/await deals with this. Figuring out the proper times to use the two I think is going to be a key skill to learn in the next few years.

Sachs Barber

unread,
Jul 16, 2012, 4:58:34 PM7/16/12
to wpf-di...@googlegroups.com, wpf-di...@googlegroups.com
I don't I worked with one guy who was using ex everywhere and it was screwed man. Reactive mvvm being a good example of why. At least in my opinion.

Like you say when needed it can be great

Sent from my iPhone

Sachs Barber

unread,
Jul 16, 2012, 5:02:13 PM7/16/12
to wpf-di...@googlegroups.com, wpf-di...@googlegroups.com
I would find told syntax more agreeable for that but hey I guess I just prefer it

Sent from my iPhone

Sachs Barber

unread,
Jul 16, 2012, 5:04:44 PM7/16/12
to wpf-di...@googlegroups.com, wpf-di...@googlegroups.com
Sorry my message made no sense reactive mvvm is good I feel is what I meant to say, but some ex stuff is so over the top

Sent from my iPhone

Peter O'Hanlon

unread,
Jul 16, 2012, 5:10:30 PM7/16/12
to wpf-di...@googlegroups.com
It's like everything else. Use it when you need it. We do some stuff with it where we need to spatially aggregate mapping information based on OS updates (that's Ordnance Survey), and we have a gnarly transformation process going on in there. Without RX, this is a huge piece of plumbing, but with Rx, it's much, much more manageable. We're talking about 500 lines of plumbing code reduced to 30 lines or so. And yes, Colin, you have to be very, very careful with exception handling, which is why we use a transactional wrapper around Rx to manage it (basically, we have a heavy use KTM library that we hook into for the file manipulation).
--
Peter O'Hanlon

Laurent Bugnion

unread,
Jul 16, 2012, 6:41:53 PM7/16/12
to wpf-di...@googlegroups.com
Having to work on an app that I didn't write and that uses RX these days
(Rich can testify...) and I find RX to be horror to debug. I never liked it
much before, but now I am quite decided to never use it ever again, and to
strongly recommend against it.

Cheers,
Laurent

-----Original Message-----
From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com]
On Behalf Of Sachs Barber
Sent: Monday, 16 July, 2012 23:02
To: wpf-di...@googlegroups.com
Cc: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Knockout Style Observables in XAML

Peter O'Hanlon

unread,
Jul 16, 2012, 7:03:19 PM7/16/12
to wpf-di...@googlegroups.com
Laurent. It's a tool (like many of the devs who misuse it). In the right hands, it's a powerful thing to use. It just takes a delicate touch, and the knowledge not to overuse it.
--
Peter O'Hanlon

Sachs Barber

unread,
Jul 17, 2012, 12:53:51 AM7/17/12
to wpf-di...@googlegroups.com, wpf-di...@googlegroups.com
One rx to rule them all and in the darkness bind them eh

Sent from my iPhone

Michael Brown

unread,
Jul 17, 2012, 4:54:25 AM7/17/12
to wpf-di...@googlegroups.com

I’ve been on a Functional Programming craze lately (especially loving Erlang) and appreciate the power that Rx brings to .NET. Like the saying goes though…any system of significant size has a half-baked, bug-ridden ad-hoc implementation of half of what Lisp can do.

;)

Laurent Bugnion

unread,
Jul 17, 2012, 1:28:28 PM7/17/12
to wpf-di...@googlegroups.com

Dan, read your latest article. I have an item on my backlog for mvvm light to solve that issue. I am currently looking into three different possible approaches:

 

·         A DependsOn attribute that would take a property name or an expression

·         A class where objects cab register their properties and the relationships between them (like Josh’s PropertyObserver)

·         Or something like you write about.

 

Users of mvvm light seem to lean toward the DependsOn attribute. I kind of like it too, it is elegant in that it can be added as an afterthought while your solution requires some upfront thinking (because you have to use a special type). Do you have thoughts about that?

 

Cheers,

Laurent

 

--

Laurent Bugnion Senior Director, Europe, IdentityMine
Microsoft MVP, MCP  | +41 79 537 78 08

www.galasoft.ch | blog.galasoft.ch | www.identitymine.com

Description: Description: Description: Description: cid:3353395316_25087103    MVPLogoHorizontal_99x40

image001.png
image002.png

Peter O'Hanlon

unread,
Jul 17, 2012, 1:51:38 PM7/17/12
to wpf-di...@googlegroups.com
When your property depends on many other properties, how would this look? Would you be stacking them?
 
[DependsOn("Title")]
[DependsOn("Forename")]
[DependsOn("Surname")]
public property FullName
{
  get return string.Format("{0} {1} {2}", Title, Forename, Surname);
}
Syntactically, this looks fairly cumbersome to me. I take it you are planning something more elegant.
--
Peter O'Hanlon
image001.png
image002.png

Daniel Vaughan

unread,
Jul 17, 2012, 3:38:46 PM7/17/12
to wpf-di...@googlegroups.com
Laurent, I agree with Pete. It's too verbose for my liking. I'm also not keen on the literal strings. It looks like the old INPC property name literals that we've been trying to get away from. I'd prefer the wrapper approach.

--
 

image001.png
image002.png

Laurent Bugnion

unread,
Jul 17, 2012, 3:56:17 PM7/17/12
to wpf-di...@googlegroups.com

Where I support property names as string, I also support expressions (lambdas), so that concern is OK. For strings I use constants anyway so it’s not that big a deal (I was never too concerned about that particular issue to be honest).

 

Verbosity… yeah I agree but on the other hand dependencies between properties can easily be added without touching the property itself, so that is an advantage…

 

Maybe I can come up with a better syntax, something like DependsOn(() => Property1 && Property2), that would be cool but not sure if doable.

 

Cheers,

Laurent

image001.png
image002.png

Sachs Barber

unread,
Jul 17, 2012, 5:21:35 PM7/17/12
to wpf-di...@googlegroups.com, <wpf-disciples@googlegroups.com>
Marlon did exactly that a while back I think

Sent from my iPhone

<image001.png>    <image002.png>




--
Peter O'Hanlon

Daniel Vaughan

unread,
Jul 17, 2012, 5:31:23 PM7/17/12
to Laurent Bugnion, wpf-di...@googlegroups.com
Another downside is that using an attribute also duplicates the fact that a dependency exists. Once for the attribute and once within the property logic. You have to keep both in sync.


Sent from my Windows Phone

From: Laurent Bugnion
Sent: 17/07/2012 21:57

To: wpf-di...@googlegroups.com
Subject: RE: [WPF Disciples] Knockout Style Observables in XAML

Description: Description: Description: Description: cid:3353395316_25087103    MVPLogoHorizontal_99x40

 

From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com] On Behalf Of Michael Brown




--
Peter O'Hanlon

image001.png
image002.png
Reply all
Reply to author
Forward
0 new messages