Skip to content

Commit 2f3fcc7

Browse files
Todd Bermananaisbetts
authored andcommitted
Add a ReactiveCollectionViewController
This is just copy pasta from ReactiveTableViewController, which seems to be the right way to handle this unfortunately? Should I be doing something different?
1 parent 01e8645 commit 2f3fcc7

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
using System;
2+
using ReactiveUI;
3+
using System.Runtime.Serialization;
4+
using System.ComponentModel;
5+
using System.Reflection;
6+
using System.Reactive.Subjects;
7+
using System.Reactive.Concurrency;
8+
using System.Linq;
9+
using System.Threading;
10+
using System.Reactive.Disposables;
11+
using System.Diagnostics.Contracts;
12+
using System.Runtime.CompilerServices;
13+
using System.Collections.Generic;
14+
using System.Drawing;
15+
16+
using MonoTouch.Foundation;
17+
using MonoTouch.UIKit;
18+
19+
namespace ReactiveUI.Cocoa
20+
{
21+
public abstract class ReactiveCollectionViewController : UICollectionViewController, IReactiveNotifyPropertyChanged, IHandleObservableErrors
22+
{
23+
protected ReactiveCollectionViewController(UICollectionViewLayout withLayout) : base(withLayout) { setupRxObj(); }
24+
protected ReactiveCollectionViewController(string nibName, NSBundle bundle) : base(nibName, bundle) { setupRxObj(); }
25+
protected ReactiveCollectionViewController(IntPtr handle) : base(handle) { setupRxObj(); }
26+
protected ReactiveCollectionViewController(NSObjectFlag t) : base(t) { setupRxObj(); }
27+
protected ReactiveCollectionViewController(NSCoder coder) : base(coder) { setupRxObj(); }
28+
protected ReactiveCollectionViewController() { setupRxObj(); }
29+
30+
[field:IgnoreDataMember]
31+
public event PropertyChangingEventHandler PropertyChanging;
32+
33+
[field:IgnoreDataMember]
34+
public event PropertyChangedEventHandler PropertyChanged;
35+
36+
/// <summary>
37+
/// Represents an Observable that fires *before* a property is about to
38+
/// be changed.
39+
/// </summary>
40+
[IgnoreDataMember]
41+
public IObservable<IObservedChange<object, object>> Changing {
42+
get { return changingSubject; }
43+
}
44+
45+
/// <summary>
46+
/// Represents an Observable that fires *after* a property has changed.
47+
/// </summary>
48+
[IgnoreDataMember]
49+
public IObservable<IObservedChange<object, object>> Changed {
50+
get { return changedSubject; }
51+
}
52+
53+
[IgnoreDataMember]
54+
protected Lazy<PropertyInfo[]> allPublicProperties;
55+
56+
[IgnoreDataMember]
57+
Subject<IObservedChange<object, object>> changingSubject;
58+
59+
[IgnoreDataMember]
60+
Subject<IObservedChange<object, object>> changedSubject;
61+
62+
[IgnoreDataMember]
63+
long changeNotificationsSuppressed = 0;
64+
65+
[IgnoreDataMember]
66+
readonly ScheduledSubject<Exception> thrownExceptions = new ScheduledSubject<Exception>(Scheduler.Immediate, RxApp.DefaultExceptionHandler);
67+
68+
[IgnoreDataMember]
69+
public IObservable<Exception> ThrownExceptions { get { return thrownExceptions; } }
70+
71+
[OnDeserialized]
72+
void setupRxObj(StreamingContext sc) { setupRxObj(); }
73+
74+
void setupRxObj()
75+
{
76+
changingSubject = new Subject<IObservedChange<object, object>>();
77+
changedSubject = new Subject<IObservedChange<object, object>>();
78+
79+
allPublicProperties = new Lazy<PropertyInfo[]>(() => GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).ToArray());
80+
}
81+
82+
/// <summary>
83+
/// When this method is called, an object will not fire change
84+
/// notifications (neither traditional nor Observable notifications)
85+
/// until the return value is disposed.
86+
/// </summary>
87+
/// <returns>An object that, when disposed, reenables change
88+
/// notifications.</returns>
89+
public IDisposable SuppressChangeNotifications()
90+
{
91+
Interlocked.Increment(ref changeNotificationsSuppressed);
92+
return Disposable.Create(() => Interlocked.Decrement(ref changeNotificationsSuppressed));
93+
}
94+
95+
protected internal void raisePropertyChanging(string propertyName)
96+
{
97+
Contract.Requires(propertyName != null);
98+
99+
if (!areChangeNotificationsEnabled || changingSubject == null)
100+
return;
101+
102+
var handler = this.PropertyChanging;
103+
if (handler != null) {
104+
var e = new PropertyChangingEventArgs(propertyName);
105+
handler(this, e);
106+
}
107+
108+
notifyObservable(new ObservedChange<object, object>() {
109+
PropertyName = propertyName, Sender = this, Value = null
110+
}, changingSubject);
111+
}
112+
113+
protected internal void raisePropertyChanged(string propertyName)
114+
{
115+
Contract.Requires(propertyName != null);
116+
117+
this.Log().Debug("{0:X}.{1} changed", this.GetHashCode(), propertyName);
118+
119+
if (!areChangeNotificationsEnabled || changedSubject == null) {
120+
this.Log().Debug("Suppressed change");
121+
return;
122+
}
123+
124+
var handler = this.PropertyChanged;
125+
if (handler != null) {
126+
var e = new PropertyChangedEventArgs(propertyName);
127+
handler(this, e);
128+
}
129+
130+
notifyObservable(new ObservedChange<object, object>() {
131+
PropertyName = propertyName, Sender = this, Value = null
132+
}, changedSubject);
133+
}
134+
135+
protected bool areChangeNotificationsEnabled {
136+
get {
137+
return (Interlocked.Read(ref changeNotificationsSuppressed) == 0);
138+
}
139+
}
140+
141+
internal void notifyObservable<T>(T item, Subject<T> subject)
142+
{
143+
try {
144+
subject.OnNext(item);
145+
} catch (Exception ex) {
146+
this.Log().ErrorException("ReactiveObject Subscriber threw exception", ex);
147+
thrownExceptions.OnNext(ex);
148+
}
149+
}
150+
151+
/// <summary>
152+
/// RaiseAndSetIfChanged fully implements a Setter for a read-write
153+
/// property on a ReactiveObject, using CallerMemberName to raise the notification
154+
/// and the ref to the backing field to set the property.
155+
/// </summary>
156+
/// <typeparam name="TObj">The type of the This.</typeparam>
157+
/// <typeparam name="TRet">The type of the return value.</typeparam>
158+
/// <param name="This">The <see cref="ReactiveObject"/> raising the notification.</param>
159+
/// <param name="backingField">A Reference to the backing field for this
160+
/// property.</param>
161+
/// <param name="newValue">The new value.</param>
162+
/// <param name="propertyName">The name of the property, usually
163+
/// automatically provided through the CallerMemberName attribute.</param>
164+
/// <returns>The newly set value, normally discarded.</returns>
165+
public TRet RaiseAndSetIfChanged<TRet>(
166+
ref TRet backingField,
167+
TRet newValue,
168+
[CallerMemberName] string propertyName = null)
169+
{
170+
Contract.Requires(propertyName != null);
171+
172+
if (EqualityComparer<TRet>.Default.Equals(backingField, newValue)) {
173+
return newValue;
174+
}
175+
176+
raisePropertyChanging(propertyName);
177+
backingField = newValue;
178+
raisePropertyChanged(propertyName);
179+
return newValue;
180+
}
181+
182+
/// <summary>
183+
/// Use this method in your ReactiveObject classes when creating custom
184+
/// properties where raiseAndSetIfChanged doesn't suffice.
185+
/// </summary>
186+
/// <param name="This">The instance of ReactiveObject on which the property has changed.</param>
187+
/// <param name="propertyName">
188+
/// A string representing the name of the property that has been changed.
189+
/// Leave <c>null</c> to let the runtime set to caller member name.
190+
/// </param>
191+
public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
192+
{
193+
raisePropertyChanged(propertyName);
194+
}
195+
196+
/// <summary>
197+
/// Use this method in your ReactiveObject classes when creating custom
198+
/// properties where raiseAndSetIfChanged doesn't suffice.
199+
/// </summary>
200+
/// <param name="This">The instance of ReactiveObject on which the property has changed.</param>
201+
/// <param name="propertyName">
202+
/// A string representing the name of the property that has been changed.
203+
/// Leave <c>null</c> to let the runtime set to caller member name.
204+
/// </param>
205+
public void RaisePropertyChanging([CallerMemberName] string propertyName = null)
206+
{
207+
raisePropertyChanging(propertyName);
208+
}
209+
}
210+
}

0 commit comments

Comments
 (0)