Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event fires more and more times

I have a silverlight mvvm application that loads main view with 2 user controls loaded into 2 ContentControls, one with listbox showing items and other with edit button. When i click edit button, 2 new user controls load into the ContentControls, one showing data to edit (EditData) and other having Save and Cancel button (EditAction). When i click save button, it raises an event that is defined in seperate GlobalEvents.cs class like:

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

and i subscribe to it in the other user control EditData, because i need to transfer that edited data via custom EventArgs, so i have put in the constructor of it's ViewModel:

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

and in the Save data:

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

which raises another event that loads previous user controls into their ControlContent and shows edited data in list box. Thats all fine, but whenever i click on edit and then save again, it raises the event twice, and again 3 times, then 4 and so on. How can i make it to be raised only ONE time? I thought it could be because every time i click edit, a new instance of the user control is loaded and i dont know, maybe the subscription to the event stays, so i have tried to paste

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

to the Dispose() method but without success. How can i make this work?

like image 736
deckard cain Avatar asked Jun 01 '11 11:06

deckard cain


2 Answers

You can't use lambdas when you want to unregister from events.

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

This will create one instance - let's call it instance A - of type EventHandler and add it as a handler.

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

This will not remove instance A from the event but create a new instance - instance B - and tries to remove it from the event.

To fix this problem, either create a little method or save that anonymous method in a field:

class ViewModel
{

    private EventHandler _saveButtonClickedHandler;
    // ...

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

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

    // ...
}
like image 73
Daniel Hilgarth Avatar answered Sep 22 '22 15:09

Daniel Hilgarth


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

This line is being called multiple times so you are adding a new event handler every time.

You need to either move that line to somewhere where it's only called once or change the event handler to:

this.globalEvents.OnSaveButtonClicked += SaveData;

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

So you remove the event handler after dealing with it. This assumes that the handler will be added back next time you go into edit mode.

like image 37
ChrisF Avatar answered Sep 23 '22 15:09

ChrisF