2011-05-05 86 views
1

我有一個WPF視圖有一個相應的ViewModel。所有實例都通過統一容器解決。因爲我使用棱鏡,所以我需要兩個獨立的視圖實例將其添加到視圖註冊到的兩個不同區域。如果我想嘗試一個實例添加到這兩個區域,我得到一個有沒有配置TransientLifetimeManager

InvalidOperationException異常:指定 元素已經是另一個元素的邏輯子 。首先斷開它 。

當視圖被添加到第二個區域時,因爲它已被添加到第一個區域。

這個問題很容易通過使用一個總是返回一個新實例的TransientLifetimeManager來解決,因此這兩個區域都會被一個獨立實例填充。

但是我們決定在新用戶登錄時創建一個子容器。每個會話相關的視圖和視圖模型都使用此子容器進行解析。當用戶的會話結束時,處理子容器,以便還處置每個與會話有關的實例。但是使用TransientLifetimeManager時,統一容器不能處理這些實例。

我們需要的是一個總是返回一個新實例但也能夠處理這些實例的終生管理器。有沒有這樣的人生經理?還是有另一種方法來實現我上面描述的?

+0

對於那些閱讀答案的人:「使有資格成爲GC'ed」並不意味着要求[立即或技術上的]處置「。對於嚴格的範圍/壽命來說,這是一個很大的差異。 – user2864740 2015-03-03 21:47:56

回答

1

當您使用瞬態生存管理器(這是默認值)時,Unity不保留對創建實例的引用。

因此,當沒有更多的實例引用時,它將被GCed。

+0

就我們所用的「視圖模型第一方法」而言,我們仍然有參考文獻。視圖和視圖模型之間有一個循環引用,它使用視圖模型將自己設置爲視圖的數據上下文。 – PVitt 2011-05-05 12:32:01

+1

循環引用如果它們是島的一部分,也應該被GCed。確保沒有其他方法可以達到循環參考 – 2011-05-05 17:02:42

2

你想要的聲音聽起來像是一個ContainerControlledLifetime管理器的變體,它不維護單例實例,而是一組實例。不幸的是,這不是內置的終生管理者之一。

你可以看看code for the ContainerControlledLifetimeManager,看看它很簡單。您的「SynchronizedGetValue」實現將始終返回null(向容器發信號通知需要實例化新實例)。您可以繼承ContainerControlledLifetimeManager並覆蓋該方法。

我寫了很多東西。我想我可以給你的代碼。 :)

public class ContainerTrackedTransientLifetimeManager :  
      ContainerControlledLifetimeManager 
{ 
    protected override object SynchronizedGetValue() 
    { 
     return null; 
    } 
} 

這應該工作。我沒有測試它...從界面看來,它看起來像是爲1到1的LifetimeManager到Object的關係設計的,但是如果事實證明它不止這些,你可能需要重寫SetValue(添加到集合的物體)並處置(處理那些物體的集合)。這是實施:

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(); 
    } 

我不確定這些是正確的答案。讓我知道它是如何爲你。

+0

是的,我昨天也試過這個。我的第一個方法以及你的兩個方法都會爲每個解決方案創建一個新實例,但當容器關閉時,所有這三個方法都不會在已解析的對象上調用Dispose。我錯過了什麼? – PVitt 2011-05-06 07:43:36

+0

該死的。我只是錯過了類定義中的IDisposable接口。該實現存在,但該對象無法投射到IDisposable。儘管如此,我最終從HierarchicalLifetimeManager派生出了ContainerTrackedTransientLifetimeManager,以便在處理子容器時處理實例。 – PVitt 2011-05-06 09:59:15

+0

我認爲這個想法是正確的,但是如果不修補Unity本身就無法完成。如果我從HierarchicalLifetimeManager派生,我的SynchronizedGetValue方法不會被調用。如果我派生自ContainerControllerLifetimeManager,則在處理子容器時不會處理該實例。因此我需要一個定製的BuilderStartegy。但是這需要訪問LifetimeManager的Internel字段IsUsed。所以我擔心這不能在大會之外實現。 – PVitt 2011-05-06 11:29:20