Skip to content

Commit 8c592f8

Browse files
author
Paul Betts
committed
Merge pull request #507 from reactiveui/xaml-memleaks
Audit all of the WhenAnys in the XAML platform library
2 parents 05d643b + 51e65d7 commit 8c592f8

File tree

2 files changed

+32
-22
lines changed

2 files changed

+32
-22
lines changed

ReactiveUI.Platforms/Xaml/CreatesCommandBinding.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ public IDisposable BindCommandToObject(ICommand command, object target, IObserva
5050
.Select(x => new { EventInfo = type.GetRuntimeEvent(x.Item1), Args = x.Item2 })
5151
.FirstOrDefault(x => x.EventInfo != null);
5252

53-
if (eventInfo == null) return null;
53+
if (eventInfo == null) {
54+
throw new Exception(
55+
String.Format(
56+
"Couldn't find a default event to bind to on {0}, specify an event expicitly",
57+
target.GetType().FullName));
58+
}
5459

5560
var mi = GetType().GetRuntimeMethods().First(x => x.Name == "BindCommandToObject" && x.IsGenericMethod);
5661
mi = mi.MakeGenericMethod(eventInfo.Args);
@@ -128,4 +133,4 @@ public IDisposable BindCommandToObject<TEventArgs>(ICommand command, object targ
128133
return null;
129134
}
130135
}
131-
}
136+
}

ReactiveUI.Platforms/Xaml/RoutedViewHost.cs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace ReactiveUI.Xaml
2323
/// the View and wire up the ViewModel whenever a new ViewModel is
2424
/// navigated to. Put this control as the only control in your Window.
2525
/// </summary>
26-
public class RoutedViewHost : TransitioningContentControl
26+
public class RoutedViewHost : TransitioningContentControl, IViewFor
2727
{
2828
IDisposable _inner = null;
2929

@@ -57,6 +57,9 @@ public IObservable<string> ViewContractObservable {
5757

5858
public IViewLocator ViewLocator { get; set; }
5959

60+
// NB: This is just a scam to get WhenActivated
61+
object IViewFor.ViewModel { get; set; }
62+
6063
public RoutedViewHost()
6164
{
6265
HorizontalContentAlignment = HorizontalAlignment.Stretch;
@@ -83,25 +86,27 @@ public RoutedViewHost()
8386
this.WhenAnyObservable(x => x.ViewContractObservable),
8487
(vm, contract) => Tuple.Create(vm, contract));
8588

86-
// NB: The DistinctUntilChanged is useful because most views in
87-
// WinRT will end up getting here twice - once for configuring
88-
// the RoutedViewHost's ViewModel, and once on load via SizeChanged
89-
vmAndContract.DistinctUntilChanged().Subscribe(x => {
90-
if (x.Item1 == null) {
91-
Content = DefaultContent;
92-
return;
93-
}
94-
95-
var viewLocator = ViewLocator ?? ReactiveUI.ViewLocator.Current;
96-
var view = viewLocator.ResolveView(x.Item1, x.Item2) ?? viewLocator.ResolveView(x.Item1, null);
97-
98-
if (view == null) {
99-
throw new Exception(String.Format("Couldn't find view for '{0}'.", x.Item1));
100-
}
101-
102-
view.ViewModel = x.Item1;
103-
Content = view;
104-
}, ex => RxApp.DefaultExceptionHandler.OnNext(ex));
89+
this.WhenActivated(d => {
90+
// NB: The DistinctUntilChanged is useful because most views in
91+
// WinRT will end up getting here twice - once for configuring
92+
// the RoutedViewHost's ViewModel, and once on load via SizeChanged
93+
d(vmAndContract.DistinctUntilChanged().Subscribe(x => {
94+
if (x.Item1 == null) {
95+
Content = DefaultContent;
96+
return;
97+
}
98+
99+
var viewLocator = ViewLocator ?? ReactiveUI.ViewLocator.Current;
100+
var view = viewLocator.ResolveView(x.Item1, x.Item2) ?? viewLocator.ResolveView(x.Item1, null);
101+
102+
if (view == null) {
103+
throw new Exception(String.Format("Couldn't find view for '{0}'.", x.Item1));
104+
}
105+
106+
view.ViewModel = x.Item1;
107+
Content = view;
108+
}, ex => RxApp.DefaultExceptionHandler.OnNext(ex)));
109+
});
105110
}
106111
}
107112
}

0 commit comments

Comments
 (0)