【问题标题】:Binding a ReactiveCommand prevents a ViewModel from being garbage collected绑定 ReactiveCommand 可以防止 ViewModel 被垃圾收集
【发布时间】:2015-04-06 21:54:49
【问题描述】:

当我在 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?非常感谢!

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    这样做之后,我可以根据需要多次访问该页面,并且永远看不到分析器中剩余的实例。

    我会等待将此标记为答案,以便给真正的专家一些时间来建议另一种(更好的?)方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 2021-01-18
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      相关资源
      最近更新 更多