Click here to Skip to main content
15,881,248 members
Articles / Programming Languages / C#
Article

The best of reactive framework extensions

Rate me:
Please Sign up or sign in to vote.
4.98/5 (16 votes)
20 Feb 2014LGPL32 min read 46.2K   504   44   32
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 :

C#
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 

C#
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 :

C#
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:

C#
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.

C#
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

C#
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 :

C#
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.

C#
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.

C#
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 :

C#
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)

C#
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, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer Freelance
France France
I am currently the CTO of Metaco, we are leveraging the Bitcoin Blockchain for delivering financial services.

I also developed a tool to make IaaS on Azure more easy to use IaaS Management Studio.

If you want to contact me, go this way Smile | :)

Comments and Discussions

 
QuestionIssue Pin
Clifford Nelson5-Apr-18 11:17
Clifford Nelson5-Apr-18 11:17 
GeneralMy vote of 5 Pin
D V L11-Jan-16 2:56
professionalD V L11-Jan-16 2:56 
QuestionQuestion regarding your ObserveEachItem extension Pin
Sacha Barber12-Mar-14 0:09
Sacha Barber12-Mar-14 0:09 
AnswerRe: Question regarding your ObserveEachItem extension Pin
Nicolas Dorier12-Mar-14 2:11
professionalNicolas Dorier12-Mar-14 2:11 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber12-Mar-14 2:43
Sacha Barber12-Mar-14 2:43 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber9-May-14 1:24
Sacha Barber9-May-14 1:24 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Nicolas Dorier9-May-14 1:35
professionalNicolas Dorier9-May-14 1:35 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber9-May-14 22:06
Sacha Barber9-May-14 22:06 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Nicolas Dorier10-May-14 0:27
professionalNicolas Dorier10-May-14 0:27 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber10-May-14 3:06
Sacha Barber10-May-14 3:06 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Nicolas Dorier10-May-14 3:43
professionalNicolas Dorier10-May-14 3:43 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber10-May-14 7:10
Sacha Barber10-May-14 7:10 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Sacha Barber10-May-14 7:21
Sacha Barber10-May-14 7:21 
GeneralRe: Question regarding your ObserveEachItem extension Pin
Nicolas Dorier10-May-14 9:36
professionalNicolas Dorier10-May-14 9:36 
GeneralMy vote of 5 Pin
Joachim Blank25-Feb-14 1:48
Joachim Blank25-Feb-14 1:48 
GeneralRe: My vote of 5 Pin
Nicolas Dorier25-Feb-14 2:17
professionalNicolas Dorier25-Feb-14 2:17 
QuestionFor us older coders: Pin
Jerry W. Manweiler, Ph.D.24-Feb-14 8:08
Jerry W. Manweiler, Ph.D.24-Feb-14 8:08 
AnswerRe: For us older coders: Pin
Nicolas Dorier24-Feb-14 8:43
professionalNicolas Dorier24-Feb-14 8:43 
GeneralRe: For us older coders: Pin
Jerry W. Manweiler, Ph.D.24-Feb-14 9:36
Jerry W. Manweiler, Ph.D.24-Feb-14 9:36 
GeneralRe: For us older coders: Pin
Nicolas Dorier24-Feb-14 11:15
professionalNicolas Dorier24-Feb-14 11:15 
QuestionMy vote of -1 Pin
Paulo Zemek23-Feb-14 15:35
mvaPaulo Zemek23-Feb-14 15:35 
AnswerRe: My vote of -1 Pin
Nicolas Dorier24-Feb-14 0:08
professionalNicolas Dorier24-Feb-14 0:08 
QuestionI use Rx a lot in my code Pin
Sacha Barber21-Feb-14 0:38
Sacha Barber21-Feb-14 0:38 
AnswerRe: I use Rx a lot in my code Pin
Nicolas Dorier21-Feb-14 1:50
professionalNicolas Dorier21-Feb-14 1:50 
AnswerRe: I use Rx a lot in my code Pin
Nicolas Dorier24-Feb-14 0:10
professionalNicolas Dorier24-Feb-14 0:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.