views:

100

answers:

2

I have an INotifyPropertyChanged object, Foo. I turn Foo into an observable stream of events using Rx's FromEvent method:

var myFoo = new Foo();
var eventStream = Observable.FromEvent<PropertyChangedEventArgs>(myFoo, "PropertyChanged");

Now I want to listen for a particular property changed, and if .Progress == 100, unsubscribe:

eventStream
   .Where(e => myFoo.Progress == 100)
   .Subscribe(OnFooFinished);

How can I unsubscribe when Progress == 100? If I add a .Take(1) call after the .Where clause, would that automatically unsubscribe?

+2  A: 

One option is to use return value of Subscribe:

IDisposable subscription = eventStream.Where(e => myFoo.Progress == 100)
                                      .Subscribe(OnFooFinished);

...

// Unsubscribe
subscription.Dispose();

I suspect that using Take(1) would indeed unsubscribe though, and it may be neater for you. Having looked at it a bit, I'm pretty sure this would unsubscribe, as it'll fire the "completed" message, which generally unsubscribes automatically. I don't have time to check this for sure at the moment, I'm afraid :(

Jon Skeet
I realize I could call Dispose. Unfortunately, I would need to call Dispose inside the OnFooFinished handler, which doesn't have a reference to the IDisposable. However, if Take(1) does the trick, that would be absolutely brilliant. I'm going to trust the almighty Skeet on this one. If it fails, I'll tell my team Skeet is to blame. :-)
Judah Himango
@Judah: LOL. I'm sure that `OnFooFinished` won't be called again, at the very least. Assuming the actual unsubscription is important though, it would be worth checking that. I can look into it in a few hours, if that's any help.
Jon Skeet
Ah, you don't have to do the work for me. I'll check it out. Thanks though. I'll let you know what I find.
Judah Himango
This thread seems to suggest that yes, Dispose will be called automatically when OnCompleted is invoked, and that all subscribers will be automatically unsubscribed through this process: http://social.msdn.microsoft.com/Forums/en/rx/thread/269cd22a-259c-4780-a2f5-94c77469eddd
Judah Himango
@Judah: Well found - that does seem to confirm it, and it would certainly make sense.
Jon Skeet
+2  A: 

You could use the TakeWhile method:

eventStream.TakeWhile(e => myFoo.Progress != 100);

TakeWhile will dispose the underlying observable sequence when its predicate returns false, you will not have to call dispose manually.

Markus Johnsson
Thanks. I need to invoke some function when myFoo.Progress == 100, though, so this doesn't quite work for my scenario. But thanks, I get the idea now.
Judah Himango