Just to be safe I will be using this pattern from now on. I will probably
modify to work via extension methods but the principle is sound. To be sure you
don't leak subscriptions you want to drop them
class Mesh2D{
public Mesh2D()
{
DisposeOnUnload(CreateBindings());
}
// Register all disposables for disposal on
// UIElement.Unload event. This should be
// moved to an extension method.
void DisposeOnUnload(IEnumerable<IDisposable> disposables)
{
var d = new CompositeDisposable(disposables);
var d2 = this.UnloadedObserver()
.Subscribe(e => d.Dispose());
var d3 = this.Dispatcher.ShutdownStartedObserver()
.Subscribe(e => d.Dispose());
d.Add(d2);
d.Add(d3);
}
// Where your bindings are simply yielded and
// they are removed on Unload magically
IEnumerable<IDisposable> CreateBindings()
{
// When the size changes we need to update all the transforms on
// the markers to reposition them.
yield return this.SizeChangedObserver()
.Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
.Subscribe(eventArgs => this.ResetImageSource());
// If the points change or the viewport changes
yield return this.WhenAny(t => t.Mesh, t => t.Viewport, (x, t) => x.Value)
.Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
.Subscribe(t => this.UpdateMeshChanged());
}
}
Note I'm wrapping RX FromEventPattern with automatically generated
extension methods so I get SizeChangedObserver() and UnloadedObserver()
for free rather than the hard to remember format of FromEventPattern.
The wrapping code is generated as such
public static IObservable<EventPattern<RoutedEventArgs>> UnloadedObserver(this FrameworkElement This){
return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => This.Unloaded += h, h => This.Unloaded -= h);
}
The above pattern could probably be used to unbind IDisposable
view models as well.