2011-06-01 47 views
7

我有一個silverlight mvvm應用程序,它將加載到2個ContentControls中的2個用戶控件加載到主視圖中,其中一個列表框顯示項目,另一個列表框顯示編輯按鈕。當我點擊編輯按鈕時,2個新的用戶控件加載到ContentControls中,一個顯示要編輯的數據(EditData)以及其他具有Save和Cancel按鈕(EditAction)的其他控件。 當我點擊保存按鈕,它提出了在單獨GlobalEvents.cs類中定義一樣的事件:事件觸發的次數越來越多

public event EventHandler OnSaveButtonClicked; 
public void RaiseSaveButtonClicked() 
{ 
    this.OnSaveButtonClicked(this, EventArgs.Empty); 
} 

,我訂閱它在其它用戶控制EditData,因爲我需要通過傳送該編輯的數據自EventArgs的,所以我已經把它的構造器的視圖模型:

this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

,並在保存數據:

public void SaveData() 
{ 
    globalEvents.RaiseSaveData(EditedGuy);  
} 

這引起了另一個前夕nt,將以前的用戶控件加載到其控件內容中,並在列表框中顯示已編輯的數據。這一切都很好,但每當我點擊編輯,然後再次保存,它會引發事件兩次,再次3次,然後4次等等。我怎樣才能讓它只被提出一次?我想這可能是因爲每次我點擊編輯,用戶控制的新實例被加載,我不知道,也許是訂閱的事件保持,所以我試圖

this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData(); 

粘貼到處置()方法但沒有成功。我怎樣才能做這項工作?

回答

7

當您想從事件中取消註冊時,不能使用lambda表達式。

this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

這將創建一個實例 - 我們稱之爲實例A - 類型爲EventHandler並將其添加爲處理程序。

this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData(); 

這不會從事件中刪除實例A,但創建一個新實例 - 實例B - 並嘗試從事件中刪除它。

要解決這個問題,可以創建一個小方法或保存匿名方法在一個領域:

class ViewModel 
{ 

    private EventHandler _saveButtonClickedHandler; 
    // ... 

    public ViewModel() 
    { 
     _saveButtonClickedHandler = (s, e) => SaveData(); 
     this.globalEvents.OnSaveButtonClicked += _saveButtonClickedHandler; 
     // ... 
    } 

    public void Dispose() 
    { 
     this.globalEvents.OnSaveButtonClicked -= _saveButtonClickedHandler; 
     // ... 
    } 

    // ... 
} 
+0

非常感謝!我不知道lambda不能用於從事件中取消註冊。我的壞,謝謝你給我正確的方式:] – 2011-06-01 11:48:39

2
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

這條線被稱爲多次,所以你每次添加一個新的事件處理程序。

您需要可以移動該行的地方在那裏它只是調用一次或更改事件處理程序:

this.globalEvents.OnSaveButtonClicked += SaveData; 

public void SaveData(object sender, EventArgs e) 
{ 
    globalEvents.RaiseSaveData(EditedGuy);  
    this.globalEvents.OnSaveButtonClicked -= SaveData(); 
} 

所以你刪除處理之後的事件處理程序。這假設處理程序將在您下一次進入編輯模式時被添加回去。

+0

謝謝你,這正是我正在尋找。 – 2011-06-01 11:47:23

+0

還有一件事,爲了讓自己明白一些事情,我嘗試將事件調用放在不同的方法中,而不是構造函數,但是在這一行的GlobalEvents類中this.OnSaveButtonClicked(this,EventArgs.Empty); 我得到空引用異常。爲什麼? – 2011-06-01 11:54:02

0

您必須輸入適當的事件處理程序方法,該方法調用SaveData()並註冊/取消註冊該方法。否則,您會嘗試取消註冊另一個「新」匿名方法,而不是您已註冊的原始方法,因爲它是匿名的,實際上無法再訪問。

public void SaveButtonClicked(object sender, EventArgs e) 
{ 
    SaveData(); 
} 

this.globalEvents.OnSaveButtonClicked += SaveButtonClicked; 

this.globalEvents.OnSaveButtonClicked -= SaveButtonClicked; 
2

你可以在類中定義的私人EventHandler委託變量,並在構造函數爲它分配:

private SaveButtonClickedHandler _handler; 

指定的處理程序在你的構造:

_handler = (s,e) => SaveData(); 
this.globalEvents.OnSaveButtonClicked += _handler; 

配置:

this.globalEvents.OnSaveButtonClicked -= _handler; 

「SaveButtonClickedHandler」是代碼的任何名稱的僞代碼/佔位符。

Hasanain

+0

這個確切的答案已經提供了近10分鐘前... – 2011-06-01 11:43:37

+0

沒錯,我沒有看到你的答案,當我第一次開始寫這個... – Hasanain 2011-06-01 11:46:10