Mvvm 是否有一个临时生命周期管理器

Mvvm 是否有一个临时生命周期管理器,mvvm,unity-container,prism,Mvvm,Unity Container,Prism,我有一个WPF视图,它有一个对应的ViewModel。所有实例都通过unity容器解析。因为我使用的是prism,所以我需要两个独立的视图实例将其添加到视图注册到的两个不同区域中。如果我尝试在两个区域中添加一个实例,我会得到一个 InvalidOperationException:已指定 元素已经是逻辑子元素 另一个元素的。断开它 首先 将视图添加到第二个区域时,因为它已添加到第一个区域 这个问题可以通过使用TransientLifetimeManager轻松解决,该管理器总是返回一个新实例,这

我有一个WPF视图,它有一个对应的ViewModel。所有实例都通过unity容器解析。因为我使用的是prism,所以我需要两个独立的视图实例将其添加到视图注册到的两个不同区域中。如果我尝试在两个区域中添加一个实例,我会得到一个

InvalidOperationException:已指定 元素已经是逻辑子元素 另一个元素的。断开它 首先

将视图添加到第二个区域时,因为它已添加到第一个区域

这个问题可以通过使用TransientLifetimeManager轻松解决,该管理器总是返回一个新实例,这样两个区域都将填充一个独立实例

但我们决定在新用户登录时创建一个子容器。每个与会话相关的视图和视图模型都使用此子容器进行解析。当用户的会话结束时,会释放子容器,以便也会释放每个与会话相关的实例。但是使用TransientLifetimeManager,unity容器无法处理这些实例


我们需要的是一个生命周期管理器,它总是返回一个新实例,但也能够处理这些实例。现在已经有这样的终身管理者了吗?或者有其他方法可以实现我上面描述的吗?

当您使用瞬态生命周期管理器(这是默认设置)时,Unity不保留对已创建实例的引用


因此,当不再引用实例时,它将被GCed。

您想要的听起来像是ContainerControlled Lifetime manager的变体,它不维护单一实例,而是实例的集合。不幸的是,这不是内置的终身管理器之一

您可以查看,它非常简单。“SynchronizedGetValue”实现将始终返回null(向容器发出需要实例化新实例的信号)。您可以将ContainerControlledLifetimeManager子类化并重写该方法

我差不多已经写好了。我想我可以给你密码。:)

这应该行得通。我还没有测试过。。。从界面上看,它似乎是为1对1 LifetimeManager到对象的关系而设计的,但如果事实证明它不止于此,那么您可能必须重写SetValue(添加到对象集合)和dispose(处置该对象集合)。以下是该实现:

public class ContainerTrackedTransientLifetimeManager : 
             SynchronizedLifetimeManager, IDisposable
{
    private ConcurrentCollection<object> values = new ConcurrentCollection<object>();

    protected override object SynchronizedGetValue()
    {
        return null;
    }

    protected override void SynchronizedSetValue(object newValue)
    {
        values.Add(newValue);
    }

    public override void RemoveValue()
    {
        Dispose();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool disposing)
    {

         var disposables = values.OfType<IDisposable>();
         foreach(var disposable in disposables)
         {
              disposable.Dispose();
         }
         values.Clear();
    }
公共类ContainerTracketTransientLifetimeManager:
SynchronizedLifetimeManager,IDisposable
{
私有ConcurrentCollection值=新ConcurrentCollection();
受保护的覆盖对象SynchronizedGetValue()
{
返回null;
}
受保护的覆盖void SynchronizedSetValue(对象newValue)
{
添加(newValue);
}
public override void RemoveValue()
{
处置();
}
公共空间处置()
{
处置(真实);
总干事(本);
}
受保护的无效处置(bool处置)
{
var disposables=value.OfType();
foreach(一次性使用的var)
{
一次性的,一次性的;
}
value.Clear();
}

我不确定哪一个是正确的答案。请告诉我您的情况。

就我们使用prism的“视图模型优先”方法而言我们仍然有引用。视图和视图模型之间有一个循环引用,它使用视图模型将自身设置为视图的数据上下文。如果循环引用是孤岛的一部分,也应该使用GCD。请确保没有其他方法可以达到循环引用是的,我昨天也尝试过。我的第一个方法也是正如你们两人所做的,每次解析都会创建一个新实例,但当容器关闭时,所有三个都不会对解析的对象调用Dispose。我缺少什么?该死。我只是错过了类定义上的IDisposable接口。实现已经存在,但对象无法强制转换为IDisposable。不过,我还是结束了从HierarchyCallifeTimeManager派生ContainerTracketTransientLifetimeManager,以便在子容器被释放时释放实例。我认为这个想法是正确的,但如果不修补Unity本身,就无法完成。如果我从HierarchyCallifeTimanager派生,则不会调用SynchronizedGetValue方法。如果我ive from ContainerController LifetimeManager在释放子容器时,该实例未被释放。因此,我需要一个自定义BuilderStartegy。但这需要访问LifetimeManager的internel字段。因此,我担心这无法从程序集外部实现。@PVitt:我今天有一些时间,所以我可能可以我自己看一看并实际试用:)与此同时,您可能需要自己跟踪对象并使用ExternallyControlled LifetimeManager。也许可以从插入子容器中的对象进行跟踪,因此您有一点需要处理,并且范围正确。@PVitt:我还想提到Damian Schenkelman关于循环引用的评论确实是正确的。只要对象图与AppDomain中的根图分离,就可以收集对象图,即使存在循环引用。.NET在技术上不使用refcount来确定GC时间。我没有提到它,因为它不是您所要求的,但您可能会这样做错误假设下的路径。对于那些阅读答案的人来说:“使符合GC'ed条件”并不“意味着调用Dispose[立即,或在技术上]”。对于严格的作用域/生命周期,这是一个很大的区别。
public class ContainerTrackedTransientLifetimeManager : 
             SynchronizedLifetimeManager, IDisposable
{
    private ConcurrentCollection<object> values = new ConcurrentCollection<object>();

    protected override object SynchronizedGetValue()
    {
        return null;
    }

    protected override void SynchronizedSetValue(object newValue)
    {
        values.Add(newValue);
    }

    public override void RemoveValue()
    {
        Dispose();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool disposing)
    {

         var disposables = values.OfType<IDisposable>();
         foreach(var disposable in disposables)
         {
              disposable.Dispose();
         }
         values.Clear();
    }