事件发生的次数越来越多

时间:2011-06-01 11:30:30

标签: c# silverlight events mvvm event-handling

我有一个silverlight mvvm应用程序,用于加载主视图,其中2个用户控件加载到2个ContentControls中,一个用列表框显示项目,另一个用编辑按钮。当我单击编辑按钮时,2个新用户控件加载到ContentControls中,一个显示要编辑的数据(EditData),另一个显示保存和取消按钮(EditAction)。 当我单击“保存”按钮时,它会引发一个在单独的GlobalEvents.cs类中定义的事件,如:

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

并且我在其他用户控件EditData中订阅它,因为我需要通过自定义EventArgs传输该编辑过的数据,所以我已经放入了它的ViewModel的构造函数:

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

并保存数据:

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

会引发另一个事件,将以前的用户控件加载到其ControlContent中,并在列表框中显示已编辑的数据。多数民众赞成,但每当我点击编辑然后再次保存时,它会将事件提升两次,然后再提高3次,然后再提高4次,依此类推。我怎样才能让它只被提升一次?我认为这可能是因为每次我点击编辑时,都会加载一个用户控件的新实例,我不知道,也许订阅该事件仍然存在,所以我试图粘贴

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

到Dispose()方法但没有成功。我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:7)

如果要取消注册事件,则无法使用lambdas。

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;
        // ...
    }

    // ...
}

答案 1 :(得分: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();
}

所以你在处理之后删除了事件处理程序。这假定下次进入编辑模式时会将处理程序添加回来。

答案 2 :(得分:2)

您可以在类中定义私有的eventhandler委托变量,并在构造函数中指定它:

private SaveButtonClickedHandler _handler;

在构造函数中分配处理程序:

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

处置:

this.globalEvents.OnSaveButtonClicked -= _handler; 

“SaveButtonClickedHandler”是伪代码/占位符,用于委托名称应该是什么。

Hasanain

答案 3 :(得分:0)

你必须输入一个适当的事件处理程序方法来调用SaveData()并注册/取消注册。否则,您尝试取消注册另一个“新”匿名方法,而不是您已注册的原始方法,因为它是匿名的,因此无法再实际访问。

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

this.globalEvents.OnSaveButtonClicked += SaveButtonClicked;

this.globalEvents.OnSaveButtonClicked -= SaveButtonClicked;