绑定ReactiveCommand可防止ViewModel被垃圾回收

时间:2015-04-06 21:54:49

标签: garbage-collection windows-store-apps reactiveui

当我将“后退按钮”绑定到ReactiveUI中的路由器时,我的ViewModel不再被垃圾收集(我的视图也是如此)。这是一个错误,还是我做了一些愚蠢的事情?

这是我的MeetingPageViewModel:

public class MeetingPageViewModel : ReactiveObject, IRoutableViewModel
{
    public MeetingPageViewModel(IScreen hs, IMeetingRef mRef)
    {
        HostScreen = hs;
    }

    public IScreen HostScreen { get; private set; }

    public string UrlPathSegment
    {
        get { return "/meeting"; }
    }
}

这是我的MeetingPage.xaml.cs文件:

public sealed partial class MeetingPage : Page, IViewFor<MeetingPageViewModel>
{
    public MeetingPage()
    {
        this.InitializeComponent();

        // ** Comment this out and both the View and VM will get garbage collected.
        this.BindCommand(ViewModel, x => x.HostScreen.Router.NavigateBack, y => y.backButton);

        // Test that goes back right away to make sure the Execute
        // wasn't what was causing the problem.
        this.Loaded += (s, a) => ViewModel.HostScreen.Router.NavigateBack.Execute(null);
    }

    public MeetingPageViewModel ViewModel
    {
        get { return (MeetingPageViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }
    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(MeetingPageViewModel), typeof(MeetingPage), new PropertyMetadata(null));

    object IViewFor.ViewModel
    {
        get { return ViewModel; }
        set { ViewModel = (MeetingPageViewModel)value; }
    }
}

然后我跑了,看看是什么,我使用VS 2013 Pro,然后打开内存分析器。我也(作为测试)投入了所有世代的强制GC收集和等待终结者。如果在上面取消注释该行,则完成所有操作后,会有三个MeetingPage和MeetingPageViewModel实例。如果我删除了BindCommand行,则没有实例。

我的印象是这些会自行消失。问题是HostScreen对象或路由器引用的对象寿命比此VM长吗?事情发生了什么?

如果是这样,建议远离后退按钮是什么?使用Splat和DI?非常感谢!

1 个答案:

答案 0 :(得分:0)

跟进我最后的想法,我可以通过以下方式解决这个问题。在我的App.xaml.cs中,我确保将RoutingState声明为依赖注入器:

        var r = new RoutingState();
        Locator.CurrentMutable.RegisterConstant(r, typeof(RoutingState));

然后,在我的Windows应用商店应用程序的后退按钮的每个视图(.xaml.cs代码)的ctor中,我不再使用上面的代码,而是将其替换为:

        var router = Locator.Current.GetService<RoutingState>();
        backButton.Click += (s, args) => router.NavigateBack.Execute(null);

在这样做之后,我可以根据需要多次访问该页面,但我从未看到分析仪中剩余的实例。

我等待将此标记为答案,让真正的专家有时间建议另一种(更好的?)方法。