代码之家  ›  专栏  ›  技术社区  ›  Tchoupi

从用于ContentControl的Ioc中的viewModel释放内存

  •  3
  • Tchoupi  · 技术社区  · 9 年前

    我当前正在使用ContentControl通过设置VM并使用默认数据模板来显示我的视图,如下所示:

    <UserControl.Resources>
        <DataTemplate DataType="{x:Type vm:MyViewViewModel}">
            <views:MyView />
        </DataTemplate>
    </UserControl.Resources>
    <ContentControl Content="{Binding ContainerContent}"/>
    

    这是我的ContainerContent:

    public ViewModelBase ContainerContent
    {
        get
        {
            return _containerContent;
        }
        set
        {
            if (_containerContent != null)
                _containerContent.Cleanup();
    
            _containerContent = value;
            RaisePropertyChanged("ContainerContent");
        }
    }
    

    我当前使用SimpleLoc通过serviceLocator加载ViewModel:

    ContainerContent = ServiceLocator.Current.GetInstance<MyViewViewModel>();
    

    这很好,可以正确显示我的视图,并将viewModel分配给内容。

    不幸的是,当我想从ContentControl中删除视图(和视图模型)时,由于ViewModel、view和SimpleDocument之间的发布顺序,我的内存仍在使用。视图曾经引用过它(我认为这个时间是由于容器上的RaisePropertyCHange之后的绑定)

    我当前使用一种方法删除内容:

     public void QuitCurrentContainerViewModel<T>() where T : class
            {
                ContainerContent = null;
                Task.Factory.StartNew(() =>
                {
                    if (/*!*/SimpleIoc.Default.ContainsCreated<T>())
                    {
                        SimpleIoc.Default.Unregister<T>();
                    }
                    DispatcherHelper.RunAsync(() =>
                    {
                        MessageBox.Show("Do GC now");
                        GC.Collect();
    
                    }, DispatcherPriority.ApplicationIdle);
                });
            }
    

    (使用调度程序和优先级是一项测试)

    如果我这样做,有时我的记忆会被正确释放,但并不总是如此。

    在任何情况下,如果我强制GC。例如,从快捷方式收集,我的内存被正确管理。

    在我的情况下,释放记忆的好方法是什么?

    谢谢

    编辑:我的错误,它与该代码配合良好(在我的QuitCurrentContainerViewModel方法中,我使用了以下检查:

    if (!SimpleIoc.Default.ContainsCreated<T>())
    

    但我需要这个:

    if (SimpleIoc.Default.ContainsCreated<T>())
    

    这样看来效果不错。

    2 回复  |  直到 9 年前
        1
  •  1
  •   ΩmegaMan    9 年前

    在我的情况下,释放记忆的好方法是什么?

    使用 IDisposable 模式,并在泛型类型说明符中要求它。这样,可以直接调用顶级实体,该实体随后可以清除其所有附着到接口的子引用。

    请记住,尽管代码中没有直接引用实例,但具有订阅的实例将变成 被钉住的 如果他们有任何活跃的订阅,则保持活跃;让垃圾收集器远离。

    必须先取消所有订阅的链接,然后才能对实例进行垃圾收集。

    如果我这样做,有时我的记忆会被正确释放,但并不总是如此。

    您正在查看应用程序的私有字节吗?因为操作系统报告了一个完整的总数,如果操作系统没有压力,它不会占用内存,让应用程序可以这么呼吸。私有字节将在完全分配的总数内上下浮动。

    因此,您可能正在监视错误的值。

        2
  •  0
  •   Tchoupi    9 年前

    这是我的代码,没有无用的调用

        public ViewModelBase ContainerContent
                {
                    get
                    {
                        return _containerContent;
                    }
                    set
                    {
                        if (_containerContent != null)
                            _containerContent.Cleanup();
    
                        _containerContent = value;
                        RaisePropertyChanged("ContainerContent");
                    }
                }
    
                public void QuitCurrentContainerViewModel<T>() where T : class
                {
                    ContainerContent = null;
                    Task.Factory.StartNew(() =>
                    {
                        if (SimpleIoc.Default.ContainsCreated<T>())
                        {
                            SimpleIoc.Default.Unregister<T>();
                            GC.Collect();
                        }
    //TODO: Do navigation or change of content    
                    });
                }
    

    这里是我装载的ContentContainer

       Task.Factory.StartNew(() =>
                {
                    if (!SimpleIoc.Default.ContainsCreated<MyViewModel>())
                        SimpleIoc.Default.Register<MyViewModel>();
                    ContainerViewModel.ContainerContent = SimpleIoc.Default.GetInstance<MyViewModel>();
                });
    

    如果有人有更好的方法来解决这个内存管理问题,我是完全开放的。