2013-04-02 95 views
3

我被搜索了一下,並且很驚訝我還沒找到更簡單的答案。我遵循一個簡單的MVVM模型,並擁有一個視圖模型(「parentVM」),該視圖模型將另一個視圖模型(「childVM」)保存爲公共屬性(get/set)公開的字段。我遇到的問題是我試圖訂閱父視圖的初始化器中的子視圖模型的屬性changed事件。但是當設置一個新的childVM時,事件處理程序會丟失。在C中的對象之間傳遞事件處理程序#

public parentVM : INotitifyPropertyChange{ 
    private _childVM = new childVM(); 

    public parentVM(){ 
     _childVM.PropertyChanged += someHandler; 
    } 


    public childVM { 
     get{ 
      return _childVM; 
     } 
     set{ 
      _childVM = value; 
      //EVENTHANDLERS ARE NOW GONE 
     } 
    } 
    .... 
} 

有沒有辦法將現有的事件處理程序轉移到新的對象?

這是一個簡化的例子。我知道,我可以簡單地招行:

_childVM.PropertyChange += someHandler; 

,但這不會爲訂閱事件外部對象的工作。在這些情況下,你不可能知道對象是什麼,處理器是什麼。

也許有一種解決方法,通過引用內部從+ = eventHandler更改爲更多手動AddHander方法的列表,然後填充列表供將來參考。在這一點上,鄧諾只是在想空間。

P.S.如果示例中存在語法錯誤,請原諒,我沒有智能感知,這不是真正的代碼......只是想表達這一點。

+0

我無法理解你想要做什麼。如果正確完成,VM屬性更改由視圖隱式處理。你不一定需要一個明確的事件處理程序。你可以給你一些你試圖完成的內容嗎? – jugg1es

回答

2

我會考慮不創建一個childVM的新實例,只是更新它的內部模型。

但是,假設你不想要這個,下面的代碼應該做你所描述的。請注意,它也會從原始的ChildVM中刪除事件處理程序(我在代碼中使用了更多的標準大寫)。未能移除事件處理程序通常會導致內存泄漏。

class ParentVM 
{ 
    private ChildVM _childVM = new ChildVM(); 

    public ParentVM() 
    { 
     _childVM.PropertyChanged += SomeHandler; 
    } 

    public ChildVM ChildVM 
    { 
     get 
     { 
      return _childVM; 
     } 
     set 
     { 
      foreach (var handler in _childVM.GetPropertyChangedHandlers()) 
      { 
       _childVM.PropertyChanged -= handler; 
       value.PropertyChanged += handler; 
      } 

      _childVM = value; 
     } 
    } 

    private void SomeHandler(object sender, PropertyChangedEventArgs e) 
    { 
    } 
} 

不幸的是,你需要這個額外的方法GetPropertyChangedHandlers在你的孩子視圖模型類,因爲你不能從定義該事件類型的外部調用GetInvocationList。下面是爲ChildVM代碼:

class ChildVM : INotifyPropertyChanged 
{ 
    public PropertyChangedEventHandler[] GetPropertyChangedHandlers() 
    { 
     return PropertyChanged.GetInvocationList(). 
       OfType<PropertyChangedEventHandler>().ToArray(); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

返回替代解決方案:你確定有必要考慮外部代碼訂閱這些事件?如果你正在做簡單的數據綁定,你應該在ChildVM屬性設置時提高PropertyChanged事件,這應該在沒有所有額外代碼的情況下處理你的問題。

+0

謝謝!是的,我使用propertyChanged僅僅是一個例子。我的真實用例比數據綁定複雜一點。 – frigon

+0

您仍然可以使用EventAggregator分離事件 –

1

更好的答案:

您ParentVM執行INotifyPropertyChanged。在更改ChildVM時引發事件。訂閱ChildVM事件的外部對象可以訂閱ParentVMs屬性更改的事件,並且可以在通知他們更改時在ChildVM上更新其事件處理程序。

原來的答案: 我將創建兩個方法SubscribeChildVMEvents(ChildVM)UnsubscribeChildVMEvent(ChildVM)並在二傳手做到這一點:

set{ 
    UnsubscribeChildVMEvents(_childVM); 
      _childVM = value; 
    SubscribeChildVMEvents(_childVM); 
      //EVENTHANDLERS ARE NOW NOT GONE 
     } 

這是很好的做法,從物體移除事件處理程序。

+0

這不涉及也訂閱這些事件的外部代碼。問題是如果這實際上是必要的。 – Thorarin

+0

也許您需要在ParentVM上實現'INotifyPropertyChanged'並在更改ChildVM後引發'PropertyChanged'事件,以便外部代碼可以偵聽該事件並被提示重新訂閱新的ChildVM。 –

+0

這對我來說也是最有意義的。 – Thorarin

2

您是否考慮遷移到EventAggregator?

他們周圍有很多人,例如,在棱鏡和caliburn.micro。

基本思想是: 有一些實體可以發佈訂閱事件(即處理事件)的事件和實體。 因此,當您僅將事件發佈到EventAggregator時,您將從直接訂閱(+ =)移動到更鬆散耦合的體系結構,即 ,並且它會處理它應該爲這些事件調用處理程序的位置(多播委託像+ )

這真的很容易,你不再在你的代碼中有這種依賴。

請看看以下鏈接

MSDN Prism description of EventAggregator (very good)

caliburn.micro description of EventAggregator

相關問題