13

I have an ObservableCollection that I need to reference for a specific item. If the item is not there, I need to monitor it via Reactive Extensions for if/when the items appears, but need some help in setting up the statement. I'm still unfamiliar with how all the different Linq extensions are intended to work, so I'm not sure how to do this. Can anyone point me in the right direction?

To illustrate better, I need to something like the following:

public class myitem :INotifyPropertyChanged
{
    private string _key;
    private string _value;

    public string key
    {
        get { return _key; }
        set { _key = value; NotifyPropertyChanged("key"); }
    }

    public string myvalue
    {
        //proper getter/setter, blah, blah
    }
}

ObservableCollection<myitem> _collection = mycollection;
var x = Observable.FromEvent<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
    h => new NotifyCollectionChangedEventHandler(h),
    h => _collection.CollectionChanged += h,
    h => _collection.CollectionChanged -= h);

string keywaitingfor = "thiskey";
string valuewaitingfor = x.Where(xx => xx.key == keywaitingfor).First().myvalue;

This isn't exactly my scenario, but hopefully you can see what I'm trying to do. The ObservableCollection may contain no items to begin, and the property values come in asyncronously. I know the last line isn't right, I need to have an Observable on the class PropertyChanged event within a lambda... but am still confused about how to just get that valuewaiting for when both conditions are met.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Random
  • 1,896
  • 3
  • 21
  • 33

2 Answers2

14

The generic ObservableCollection has nothing to do with the IObservable interface. You can however monitor an ObservableCollection's CollectionChanged event through Rx using the following:

ObservableCollection<SomeType> items = yourObserableCollection;
var itemAddedObservable = Observable
         .FromEventPattern<NotifyCollectionChangedEventArgs>(items, "CollectionChanged")
         .Select(change => change.EventArgs.NewItems)

This will give you a notification whenever item(s) are added to the ObservableCollection. The items will be a non-generic IList, so we can cast that to an IEnumerable of the underlying SomeType and SelectMany on that .AsObservable to get a new observable stream of the incoming values. Finally in the Subscribe, you do what you want with the final value (rather than using the blocking First call):

var filteredAddedItem = from added in itemAddedObservable
                        from itemAdded in added.OfType<SomeType>().ToObservable()
                        where itemAdded.key = keywaitingfor
                        select itemAdded;

var sub = filteredAddedItem.Subscribe(item => Console.WriteLine("Received " + item.myvalue));
Jim Wooley
  • 10,169
  • 1
  • 25
  • 43
  • +1. One question - I have this **_keywaitingfor_** present in another collection. How do I search through or match the **_itemAdded.Key_** in that other collection ? – Angshuman Agarwal Oct 24 '14 at 10:17
8

Add ReactiveUI to your project, then you can use the ReactiveCollection class, which derives from WPF's ObservableCollection. Then this is easy as pie:

theCollection.ItemsAdded
    .Where(x => x.Key == "Foo")
    .Subscribe(x => Console.WriteLine("Received Item!"));
Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • 3
    ObservableCollection is sort of an unfortunate naming choice now :( This is bump in the road when doing Rx training. – Anderson Imes Sep 01 '11 at 06:28
  • Looks like just what I'll need. – Random Sep 01 '11 at 15:47
  • I didn't realize ReactiveUI was going to be such an extensive library. It looks great; I just wish I'd known about it a few months ago, it may not fit into my project at this point. So, while I hope I can use it in the future, and it is "an" answer, I need to deselect it as the "accepted" answer. – Random Sep 01 '11 at 17:13
  • http://blog.paulbetts.org/index.php/2011/04/04/using-reactiveui-with-mvvm-light-or-any-other-framework/ – Ana Betts Sep 01 '11 at 19:32
  • 1
    The other thing you could do is just copy-paste https://github.com/xpaulbettsx/ReactiveUI/blob/master/ReactiveUI/ReactiveCollection.cs into your project and change all of the RxApp.DeferredScheduler into DispatcherScheduler.Current – Ana Betts Sep 02 '11 at 00:58
  • Now that might work. I'll give it a shot. My pickiness before isn't a slight on your library, btw. It really does look great, and I'm going to keep it in mind for future projects. – Random Sep 02 '11 at 15:15
  • ReactiveUI is no longer supporting .Net 4.0. It has dependency Splat 1.0 which has no support for .Net 4.0. Getting following error. Could not install package 'Splat 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.0', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. – manu Aug 07 '15 at 14:57
  • I have added ReactiveUI to my project, but I cannot find ReactiveCollection – JonathanPeel Feb 08 '19 at 08:53
  • 1
    @JonathanPeel ReactiveCollection is deprecated - the library now uses Roland Pheasant's DynamicData - https://dynamic-data.org/ - which is far more powerful. – Rich Bryant Jul 17 '19 at 19:16