H,
I have a listView with an event set to ItemChecked, now i need to do something like:
var tmp = this.listView.ItemChecked;
this.listView.ItemChecked = null; //set the event to null
// run some code which checkes some item in the list
// wehre the event shouldnt get fired on
this.listView.ItemChecked = tmp; //set the event again
Problem is that i can not read the event, i get the message that it can be used only on the left side of a statement.
Any Ideas?
this.listView.ItemChecked -= myEventHandler;
// run some code
this.listView.ItemChecked += myEventHandler;
You can unsubscribe and resubscribe to do what you're trying to do:
private void listView1_ItemChecked(object sender, ItemCheckedEventArgs e)
{
listView1.ItemChecked -= new ItemCheckedEventHandler(listView1_ItemChecked);
// do stuff
listView1.ItemChecked += new ItemCheckedEventHandler(listView1_ItemChecked);
}
You could remove then add the event handler. Assuming your code is in a method named ItemChecked
listView.ItemChecked -= ItemChecked;
// do whatever
listView.ItemChecked += ItemChecked;
However, I prefer checking for re-entrant calls.
object alreadyInItemChecked;
void ItemChecked(object s, EventArgs e)
{
if (Monitor.TryEnter(alreadyInItemChecked))
{
try
{
// do whatever
}
finally
{
Monitor.Exit(alreadyInItemChecked)
}
}
}
You can subscribe / unsubscribe to events as something like this.
this.someObject.someObjectEvent += someEventHandler;
this.someObject.someObjectEvent -= null;
So subscribe when you want the event to be fired and unsubscribe when not needed.
Related
I have a code where the application is crashing because, the subscribe event should be postponed until a load method is called (While currently I am using the checkbox check property inside another method due to business rules as follows:)
private void NatureCheck(bool Rec)
{
chkRec.Checked = !(lblRecID.Visible = txtRecID.Visible = Rec);
if (!applyReadOnly)
recipientController.SaveOrNotInBook(chkRec.Checked, address);
}
The event below is triggered and app crashes.
chkRec.CheckedChanged += new System.EventHandler(chkRec_CheckedChanged);
I want to postpone triggering of this above event until "Load method" is called. How to do this, please help me.
My Load Method:
private void Rec_Load(object sender, EventArgs e)
{
if (chkRec.Visible = allowTemp)
chkRec.Enabled = !(chkRec.Checked = RecDataTable[0].CA_FLAG);
string country = RecDataTable[0].IsNTY() ? string.Empty : RecDataTable[0].NTY;
showTax(country);
dGSignatureLoaded = !(lblDGSignText.Visible = RecDataTable[0].IsDG_SIGNNull());
}
Event Handler:
private void chkRec_CheckedChanged(object sender, EventArgs e)
{
Controller.TryHandleException(delegate
{
lblRec.Visible = txtRecID.Visible = !chkRec.Checked;
if (recipientController.SaveOrNotInBook(chkRec.Checked, RecipientDataTable[0]))
recDataTableBindingSource.EndEdit();
});
}
The simplest option is just to move this line:
chkRec.CheckedChanged += new System.EventHandler(chkRec_CheckedChanged);
into the end of the Load method. Then the handler isn't attached till the Load has happened.
Note also you can detach the handler at any time as follows:
chkRec.CheckedChanged -= new System.EventHandler(chkRec_CheckedChanged);
... then reattach again using the original line of code!
Did the event handler existed when initialing the form?
How about remove the handler before the code?
private void NatureCheck
{
chkRec.CheckedChanged -= new System.EventHandler(chkRec_CheckedChanged);
chkRec.Checked = !(lblRecID.Visible = txtRecID.Visible = Recip);
chkRec.CheckedChanged += new System.EventHandler(chkRec_CheckedChanged);
}
How to remove the event handler after the event handler had fired so that it can execute only once?
c.Click += (o,e)=>{
Console.WriteLine("Clicked!");
/*I want to remove this event handler now so that it doesn't fire anymore*/
}
You need to store the event handler in a variable, so that you can refer to it later. Because you want to refer to the handler from within the handler you also need to declare it before you initialize it. Finally, you cannot use an uninitialized variable, so you need to initialize it to null first, even though that null value will never be read from.
EventHandler handler = null;
handler = (o,e)=>{
Console.WriteLine("Clicked!");
c.Click -= handler;
}
c.Click += handler;
The other option would be to use a named method, rather than an anonymous method.
This becomes easier if you use a named method instead of an anonymous lambda method.
c.Click += MyHandler;
void MyHandler(object sender, EventArgs e)
{
Console.WriteLine("Clicked!");
((Button)sender).Click -= MyHandler;
}
I've set an eventhandler to an event like this:
frm.FormClosed += (sender, args) =>
{
if (this.myGrid.Enabled)
{
this.myGrid.Select();
}
};
frm.Show();
I want to hang out the eventhandler after the form was closed.
Can you help me?
I want to hang out the eventhandler after the form was closed.
I assume you want to remove it.
Not necessary, don't waste time on it. When the Form is closed (and Disposed), the eventhandler will be collected too. It is a member of the same Form, that follows from the word this in the code.
If you still want to remove it, you will need a copy:
FormClosedEventhandler closeHandler; // class member
closeHandler = (sender, args) =>
{
if (this.myGrid.Enabled)
{
this.myGrid.Select();
}
};
frm.FormClosed += closeHandler ; // OnLoad
...
frm.FormClosed -= closeHandler ; // OnClose
If you mean how to remove you event handler from the event, then you won't be able to use an anonymous delegate but you can create a method with the same parameters and same code and then:
private void EventHandler(object sender, FormClosedEventArgs e)
{
if (this.myGrid.Enabled)
{
this.myGrid.Select();
}
}
frm.FormClosed += EventHandler; // Attach the event handler
frm.FormClosed -= EventHandler; // Remove the event handler
My understanding is that any event handlers wired up in C# need to be unwired as such.
Object myObject = new Object();
myObject.Event += EventHandler; //Wired
myObject.Event -= EventHandler; //Unwired
But do you need to unwire the following code? and if so, how?
Object myObject = new Object();
myObject.Event += (object sender, EventArgs e) => { }; //Wired
myObject.Event -= ????? //Unwire? How?
My assumption is no?
Yes, you need to (*) and you need to do it like this:
Object myObject = new Object();
EventHandler handler = (object sender, EventArgs e) => { };
myObject.Event += handler; //Wired
myObject.Event -= handler; //Unwired
See here for an explanation.
(*)
You don't need to do it because of garbage collection. You need to do it, if you don't want the event to call your handler any more.
UPDATE:
To clarify a bit:
The only reason, why you want to unwire an event handler is that the object defining the event handler can be garbage collected.
Think about the following example:
You have a class PowerSource with an event BlackOut.
You have a class LightBulb that will be on, as long as there is power. It has a method ConnectToPowerSource. This method subscribes to the BlackOut event of the supplied PowerSource.
You have a collection that contains the light bulbs
Now, simply removing a light bulb from the list will not make it get garbage collected, because the PowerSource is still holding a reference to the LightBulb instance in its BlackOut event. Only after unregistering the LightBulb from the BlackOut event will make the LightBulb get garbage collected.
Yes, you do have to. Because an event is a strong reference, your event handler will continue to be invoked.
You can remove it as follows:
EventHandler handler = (s,e) => { DoSomething(); }
myObject.Event += handler;
myObject.Event -= handler;
Object myObject = new Object();
EventHandler h = (object sender, EventArgs e) => { }; //Wired
myObject.Event += h;
myObject.Event -= h;
Or, to unwire in the handler:
Object myObject = new Object();
EventHandler h = null; //need to declare h to use it in the following line
//compiler/resharper will complain about modified closure
h = (object sender, EventArgs e) => { myObject.Event-=h; };
myObject.Event += h;
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?
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;
// ...
}
// ...
}
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.
You could define a private eventhandler delegate variable in your class and assign it in your constructor:
private SaveButtonClickedHandler _handler;
Assign the handler in your constructor:
_handler = (s,e) => SaveData();
this.globalEvents.OnSaveButtonClicked += _handler;
Dispose:
this.globalEvents.OnSaveButtonClicked -= _handler;
"SaveButtonClickedHandler" is pseudo-code/placeholder for whatever the name of the delegate should be.
Hasanain
You'll have to put in a proper event handler method that calls SaveData() and register/unregister that. Otherwise you try to unregister another "new" anonymous method instead of the original one you've registered, which you, because it is anonymous, cannot actually access anymore.
public void SaveButtonClicked(object sender, EventArgs e)
{
SaveData();
}
this.globalEvents.OnSaveButtonClicked += SaveButtonClicked;
this.globalEvents.OnSaveButtonClicked -= SaveButtonClicked;