Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The best of reactive framework extensions

0.00/5 (No votes)
20 Feb 2014 1  
An enumeration of nice code rewrite of recurring spaghetti code thanks to Reactive Framework

Introduction  

Some of you may remember my love with Rx Framework began with a pet project I wrote about.
Now, I’m using Rx Framework almost every day, but this is thanks to a small little personal framework that made my life easier.

So, no big and complicated article today, it’s friday after all, just an enumeration of my best reactive framework extensions methods.  This article can be considered as the suite of this old one that grouped some of my utility classes.

Best of 

All methods I use such as .Subscribe will return a IDisposable that you can dispose if you want to unsubscribe. 

How to subscribe to PropertyChanged

When you are interested into a property that change on some of you view model, you often need to write the following spaghetti code :

public void UpdateUser(User user)
{
    user.PropertyChanged += user_PropertyChanged;
    NameChanged();
}
void user_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "Name")
        NameChanged();
}
private void NameChanged()
{
    //Do wonderfull stuff
} 

I replaced with 

user
    .ItemPropertyChanged(u=>u.Name,true)
    .Subscribe((args) =>
    {
        //Do wonderfull stuff with args.NewValue and args.OldValue
    });

The boolean fire the subscribe action directly a first time when you subscribe. Note that you can get the NewValue and OldValue of your property with the args argument, and do not have magic string anymore.

How to subscribe to CollectionChanged

Replace the old way of doing something on each items added to an observable collection :

public void SubscribeToCollection(ObservableCollection<User> users)
{
    users.CollectionChanged += users_CollectionChanged;
    foreach(var user in users)
    {
        NewUser(user);
    }
}
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if(e.NewItems != null)
        foreach(User user in e.NewItems)
        {
            NewUser(user);
        }
}
private void NewUser(User user)
{
    //Do something
}

Into the reactive way:

users
    .ForeachItem()
    .Subscribe(user =>
    {
        //Do something
    });

How to subscribe to items in a ObservableCollection

Well basically a spaghetti code combining the two previous old approach. I replaced the following spaghetti.

public void SubscribeToCollection(ObservableCollection<User> users)
{
    users.CollectionChanged += users_CollectionChanged;
    foreach(var user in users)
    {
        NewUser(user);
    }
}
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if(e.NewItems != null)
        foreach(User user in e.NewItems)
        {
            NewUser(user);
        }
    if(e.OldItems != null)
    {
        foreach(User user in e.OldItems)
        {
            user.PropertyChanged -= UserChanged;
        }
    }
}
private void NewUser(User user)
{
    user.PropertyChanged += UserChanged;
}
void UserChanged(object sender, PropertyChangedEventArgs e)
{
    //Do wonderfull stuff when one user changes
}

Into the clean version

users
    .ObserveEachItem(u => u.ItemPropertyChanged())
    .Subscribe(args =>
    {
        User user = args.Sender;
        //Do wonderfull stuff when one user changes
    });

Weak event listener

Have you tried to subscribe to an object weakly, so the garbage collector correctly garbage a listener that is no longer referenced anywhere ? Well, one solution is to read this msdn page and use the WeakEventManager. Sorry, I’m too lazy to read it for you.

The other solution is to use my ObserveWeakly method :

var subscription = user.ItemPropertyChanged()
                    .ObserveWeakly()
                    .Subscribe(args =>
                    {
                        User u = args.Sender;
                        //User changed do what you want...
                    });
subscription = null; //OMG forgot to Dispose the subscription !!! memory leak !1!
GC.Collect();
user.AssertSubscribers(0); //Just kidding 

Subscribe to dependency property changes

The code to subscribe to dependency properties is not trivial as you can see in the following snippet.

TextBox box = new TextBox();
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(TextBox.BackgroundProperty, typeof(TextBox));
if(dpd != null)
{
    dpd.AddValueChanged(box, (sender, args) =>
    {
        //Do wonderfull stuff when the background changed
    });
}

But fear not, now you can do that.

TextBox box = new TextBox();
box.DependencyPropertyChanged<Brush>(TextBox.BackgroundProperty)
    .Subscribe(args =>
    {
        Brush brush = args.NewValue;
    });

Synchronize two ObservableCollection

I’m sure it happened to you more than once, for example you want an ObservableCollection<String> that list dynamically all the girls’ name of your ObservableCollection<User>. Here is the old way :

ObservableCollection<String> GirlsNames = new ObservableCollection<String>();
public void SubscribeToCollection(ObservableCollection<User> users)
{
    users.CollectionChanged += users_CollectionChanged;
    foreach(var user in users)
    {
        NewUser(user);
    }
}


void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if(e.NewItems != null)
        foreach(User user in e.NewItems)
        {
            NewUser(user);
        }
    if(e.OldItems != null)
    {
        foreach(User user in e.OldItems)
        {
            GirlsNames.Remove(user.Name);
        }
    }
}
private void NewUser(User user)
{
    if(user.Gender = Gender.Girl)
        GirlsNames.Add(user.Name);
}

Now you can turn this spaghetti into a single line: (Always returns a IDisposable if you want to stop the mapping)

users.MapToCollection(GirlsNames, u=>u.Name, u=> u.Gender == Gender.Girl);

Conclusion

I put the sources and binaries as this article, I also have a private GIT repository and internal Nuget feed to deploy my framework in my own projects. I intend to switch to public GIT repository and public nuget feed, if you beg me. ;)

Anyway the solution ships with full unit tests for everything, feel free to play with it, if there is more that what you need don’t hesitate to just copy/paste my code if you don’t want all.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here