事件引发的次数越来越多



我有一个silverlight mvvm应用程序,它加载主视图,其中两个用户控件加载到两个ContentControls中,一个带有显示项目的列表框,另一个带有编辑按钮。当我单击编辑按钮时,两个新的用户控件加载到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中并在列表框中显示编辑后的数据。这一切都很好,但每当我点击编辑然后再次保存时,它都会引发事件两次,三次,四次,以此类推。我怎么能让它只引发一次呢?我想这可能是因为每次我点击编辑时,都会加载一个新的用户控件实例,我不知道,也许对事件的订阅会保留下来,所以我尝试粘贴

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

到Dispose()方法,但没有成功。我该怎么做?

当您想从事件中注销时,不能使用lambdas。

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

这将创建一个EventHandler类型的实例(我们称之为实例A),并将其添加为处理程序。

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;
        // ...
    }
    // ...
}
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData();

此行被多次调用,因此每次都要添加一个新的事件处理程序。

您需要将该行移动到只调用一次的位置,或者将事件处理程序更改为:

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

因此,您在处理完事件处理程序后将其删除。这假设下次进入编辑模式时将重新添加该处理程序。

您可以在类中定义一个私有事件处理程序委托变量,并在构造函数中分配它:

private SaveButtonClickedHandler _handler;

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

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

处置:

this.globalEvents.OnSaveButtonClicked -= _handler; 

"SaveButtonClickedHandler"是伪代码/占位符,表示委托的名称。

Hasanain

您必须放入一个正确的事件处理程序方法来调用SaveData()并注册/注销它。否则,您将尝试注销另一个"新"匿名方法,而不是您已注册的原始方法,因为它是匿名的,您实际上无法再访问该方法。

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

最新更新