Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactiveCollection issues #76

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion ReactiveUI/Interfaces.cs
Expand Up @@ -157,7 +157,7 @@ public interface IReactiveCollection : IReactiveNotifyPropertyChanged, IEnumerab
/// <summary>
/// Fires when a collection becomes or stops being empty.
/// </summary>
IObservable<bool> IsEmpty { get; }
IObservable<bool> CollectionIsEmptyChanged { get; }

//
// Change Tracking
Expand Down
109 changes: 93 additions & 16 deletions ReactiveUI/ReactiveCollection.cs
Expand Up @@ -24,6 +24,8 @@ namespace ReactiveUI
/// <typeparam name="T">The type of the objects in the collection.</typeparam>
public class ReactiveCollection<T> : ObservableCollection<T>, IReactiveCollection<T>, IDisposable
{
private ISubject<NotifyCollectionChangedEventArgs> ocChangedEvent;

/// <summary>
/// Constructs a ReactiveCollection.
/// </summary>
Expand Down Expand Up @@ -53,8 +55,7 @@ void setupRx(IEnumerable<T> List = null)
foreach(var v in List) { this.Add(v); }
}

var ocChangedEvent = new Subject<NotifyCollectionChangedEventArgs>();
CollectionChanged += (o, e) => ocChangedEvent.OnNext(e);
ocChangedEvent = new Subject<NotifyCollectionChangedEventArgs>();

_ItemsAdded = ocChangedEvent
.Where(x =>
Expand Down Expand Up @@ -88,6 +89,8 @@ void setupRx(IEnumerable<T> List = null)
cleared
);

_CollectionIsEmptyChanged = CollectionCountChanged.Select(x => x == 0).DistinctUntilChanged();

_ItemChanging = new ScheduledSubject<IObservedChange<T, object>>(RxApp.DeferredScheduler);
_ItemChanged = new ScheduledSubject<IObservedChange<T,object>>(RxApp.DeferredScheduler);

Expand All @@ -107,6 +110,8 @@ void setupRx(IEnumerable<T> List = null)
new ObservedChange<object, object>() {PropertyName = "Items", Sender = this, Value = this}),
_ItemsRemoved.Select<T, IObservedChange<object, object>>(x =>
new ObservedChange<object, object>() {PropertyName = "Items", Sender = this, Value = this}),
cleared.Select<int, IObservedChange<object, object>>(x =>
new ObservedChange<object, object>() { PropertyName = "Items", Sender = this, Value = this }),
_ItemChanged.Select<IObservedChange<T, object>, IObservedChange<object, object>>(x =>
new ObservedChange<object, object>() {PropertyName = x.PropertyName, Sender = x.Sender, Value = x.Value}));

Expand All @@ -125,8 +130,6 @@ void setupRx(IEnumerable<T> List = null)
removeItemFromPropertyTracking(x);
});

IsEmpty = CollectionCountChanged.Select(x => x == 0);

#if DEBUG
_ItemChanged.Subscribe(x =>
this.Log().Debug("Object {0} changed in collection {1:X}", x, this.GetHashCode()));
Expand Down Expand Up @@ -165,6 +168,8 @@ void removeItemFromPropertyTracking(T toUntrack)
propertyChangeWatchers[toUntrack].Release();
}

#region ItemsAdded

[IgnoreDataMember]
protected IObservable<T> _ItemsAdded;

Expand All @@ -187,6 +192,10 @@ void removeItemFromPropertyTracking(T toUntrack)
get { return _BeforeItemsAdded.Where(_ => areChangeNotificationsEnabled); }
}

#endregion

#region ItemsRemoved

[IgnoreDataMember]
protected IObservable<T> _ItemsRemoved;

Expand All @@ -209,12 +218,16 @@ void removeItemFromPropertyTracking(T toUntrack)
get { return _BeforeItemsRemoved.Where(_ => areChangeNotificationsEnabled); }
}

#endregion

[IgnoreDataMember]
protected Subject<int> aboutToClear;

[IgnoreDataMember]
protected Subject<int> cleared;

#region Count

[IgnoreDataMember]
protected IObservable<int> _CollectionCountChanging;

Expand All @@ -237,6 +250,10 @@ void removeItemFromPropertyTracking(T toUntrack)
get { return _CollectionCountChanged.Where(_ => areChangeNotificationsEnabled); }
}

#endregion

#region ItemChanged

[IgnoreDataMember]
protected ISubject<IObservedChange<T, object>> _ItemChanging;

Expand Down Expand Up @@ -266,6 +283,10 @@ void removeItemFromPropertyTracking(T toUntrack)
get { return (IObservable<IObservedChange<object, object>>)ItemChanged; }
}

#endregion

#region Changed

[IgnoreDataMember]
protected IObservable<IObservedChange<object, object>> _Changing;

Expand All @@ -288,7 +309,28 @@ void removeItemFromPropertyTracking(T toUntrack)
get { return _Changed.Where(_ => areChangeNotificationsEnabled); }
}

public IObservable<bool> IsEmpty { get; protected set; }
#endregion

#region IsEmpty

[IgnoreDataMember]
protected IObservable<bool> _CollectionIsEmptyChanged;

/// <summary>
/// Fires whenever the number of items in a collection has changed,
/// providing the new Count.
/// </summary>
public IObservable<bool> CollectionIsEmptyChanged
{
get { return _CollectionIsEmptyChanged.Where(_ => areChangeNotificationsEnabled); }
}

#endregion

public bool IsEmpty
{
get { return this.Count == 0; }
}

[field:IgnoreDataMember]
public event PropertyChangingEventHandler PropertyChanging;
Expand Down Expand Up @@ -336,9 +378,11 @@ protected void releasePropChangeWatchers()
public void Reset()
{
#if !SILVERLIGHT
if (changeNotificationsSuppressed == 0 && CollectionChanged != null) {
CollectionChanged.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
//if (areChangeNotificationsEnabled && CollectionChanged != null)
//{
// CollectionChanged.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
//}
#else
// XXX: SL4 and WP7 hate on this
#endif
Expand All @@ -347,13 +391,28 @@ public void Reset()
protected override void InsertItem(int index, T item)
{
_BeforeItemsAdded.OnNext(item);

bool fireIsEmpty = this.Count == 0;

base.InsertItem(index, item);

if (fireIsEmpty)
{
this.OnPropertyChanged(new PropertyChangedEventArgs("IsEmpty"));
}
}

protected override void RemoveItem(int index)
{
_BeforeItemsRemoved.OnNext(this[index]);

base.RemoveItem(index);

bool fireIsEmpty = this.Count == 0;
if (fireIsEmpty)
{
this.OnPropertyChanged(new PropertyChangedEventArgs("IsEmpty"));
}
}

protected override void SetItem(int index, T item)
Expand All @@ -371,6 +430,8 @@ protected override void ClearItems()
// we have to release the watchers or else we leak them.
releasePropChangeWatchers();

bool fireIsEmpty = this.Count > 0;

// N.B: This is less efficient, but Clear will always trigger the
// reset, even if SuppressChangeNotifications is enabled.
using(SuppressChangeNotifications()) {
Expand All @@ -379,7 +440,13 @@ protected override void ClearItems()
}
}

Reset();
base.ClearItems();

if (fireIsEmpty)
{
this.OnPropertyChanged(new PropertyChangedEventArgs("IsEmpty"));
}

cleared.OnNext(0);
}

Expand All @@ -403,7 +470,7 @@ public IDisposable SuppressChangeNotifications()
Interlocked.Increment(ref changeNotificationsSuppressed);
return Disposable.Create(() => {
Interlocked.Decrement(ref changeNotificationsSuppressed);
RxApp.DeferredScheduler.Schedule(() => Reset());
//RxApp.DeferredScheduler.Schedule(() => Reset());
});
}

Expand Down Expand Up @@ -453,19 +520,29 @@ public IDisposable SuppressChangeNotifications()

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler handler = CollectionChanged;
ocChangedEvent.OnNext(e);

if (areChangeNotificationsEnabled)
{
NotifyCollectionChangedEventHandler handler = CollectionChanged;

if (handler != null) {
handler(this, e);
if (handler != null)
{
handler(this, e);
}
}
}

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = _propertyChangedEventHandler;
if (areChangeNotificationsEnabled)
{
PropertyChangedEventHandler handler = _propertyChangedEventHandler;

if (handler != null) {
handler(this, e);
if (handler != null)
{
handler(this, e);
}
}
}
#endif
Expand Down