A System.Reactive property change observer

I recently read Mike Taulty’s post on creating a FlickR searcher with Silverlight and Microsoft’s System.Reactive extensions. In his post, Mike says this about the way his property observer works: “That feels a bit weird and perhaps I should have passed a lambda into my FromPropertyChange wrapper function to grab the value from this.SearchText rather than do this?”

As we had implemented pretty much the exact the thing Mike describes in a recent project I thought I’d share it here (I was going to just post the code in the comments on Mikes blog but code snippets in blog comments rarely format well).

I’ll show you how to take the code that we wrote and integrate into the FlickR searcher that Mike wrote, replacing his property handler. First you’ll need to grab the code that Mike wrote – it’s available from his blog post.

Open the ObservableEx.cs file and paste the following code into the ObservableEx class.

        public static IObservable<TProperty> ObservePropertyChanges<T, TProperty>(this T notifyPropertyChanged, Expression<Func<T, TProperty>> property)
            where T : INotifyPropertyChanged
        {
            var propertyName = property.GetMemberInfo().Name;
            var func = property.Compile();

            var observablePropertyChanges = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                h => notifyPropertyChanged.PropertyChanged += h,
                h => notifyPropertyChanged.PropertyChanged -= h)
                .Where(x => x.EventArgs.PropertyName == propertyName)
                .Select(x => func.Invoke(notifyPropertyChanged));

            return observablePropertyChanges;
        }

        public static MemberInfo GetMemberInfo(this Expression expression)
        {
            var lambda = (LambdaExpression)expression;

            MemberExpression memberExpression;
            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = (UnaryExpression)lambda.Body;
                memberExpression = (MemberExpression)unaryExpression.Operand;
            }
            else memberExpression = (MemberExpression)lambda.Body;

            return memberExpression.Member;
        }

 

There are 2 methods here – GetMemberInfo is just a helper method to get a MemberInfo object from a Lambda expression. This is used so we can get a MemberInfo object for the property lambda. The first method, ObservePropertyChanges, is a bit more interesting – we pass in an object that implements INotifyPropertyChanged (note the ‘this’ keyword so we can use this as an extension method) and a Func Expression – in practice this means we will pass a property lambda in. The method returns an IObservable for the property type we passed in.

Now open up the MainViewModel.cs file and find the InitialiseSearchTextSubscription method. Comment out the code in there and paste in this code instead:

this.ObservePropertyChanges(x => x.SearchText)
                .Where(text => text.Length > Constants.MinSearchStringLength)
                .Throttle(TimeSpan.FromMilliseconds(Constants.SearchTextTimeoutMs))
                .ObserveOnDispatcher()
                .Subscribe(OnNewSearch);

 

As you can see, this is pretty similar to the code Mike had already written to do the same thing. There are two main differences. First, we’re not using a ‘magic string’ to reference the property we want to observe(SearchText in this case) – we can use a strongly typed lambda – with all the benefits that gives us re. compile time type checking, refactoring etc. Secondly we don’t have to ‘select’ the property from the object we’re observing – the value is passed to us in the observable sequence.

Hope this is useful to someone Smile

Add a Comment