I have an external application that provides an event StkQuit
.
I subscribe to this event in a static class that handles all communication between my application and [the] external application. I would like to subscribe to the StkQuit
event using another handler that sits on my form class.
This handler will inform the user that the external application has been closed. I would like to have a generic method in the static class called SubscribeToStkQuit
that accepts a delegate as a parameter and subscribes that delegate (referring to the handler on my form class) to the StkQuit
event.
Is this possible? Is this the most elegant/simplistic way to achieve such functionality?
My example code:
Form Class
public delegate void dForceClose();
public void SubscribeToStkQuit(dForceClose forceClose)
{
UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose));
}
private void ForceClose()
{
MessageBox.Show("TEST");
}
Static Class
private static AgUiApplication _stkUiApplication;
public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
_stkUiApplication.OnQuit += subscribeHandler;
}
[Update]
As per comments I have updated the code like so:
public delegate void dForceClose(object sender, EventArgs e);
public void SubscribeToStkQuit(dForceClose forceClose)
{
UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose));
}
private void ForceClose(object sender, Eventargs e)
{
MessageBox.Show("TEST");
}
I am still getting the cast exception. Any ideas ??
[Update #2]
I'm still having problems with this. In my static class I have a handler already for when OnQuit
fires:
private static AgUiApplication _stkUiApplication;
public static bool CheckThatStkIsAvailable()
{
object stkApplication = null;
try
{
stkApplication = Marshal.GetActiveObject(_stkProgId);
_stkUiApplication = stkApplication as AgUiApplication;
_stkUiApplication.OnQuit += StkQuit;
return true;
}
catch (Exception)
{
// handle this
}
}
private static void StkQuit()
{
_stkUiApplication.OnQuit -= StkQuit;
Marshal.FinalReleaseComObject(_stkUiApplication);
Marshal.FinalReleaseComObject(_stkRoot);
}
This works fine. So I thought I would create a public property for _stkUiApplication and subscribe from the form class in the same manner:
Static Class
public static AgUiApplication StkUiApplication
{
get { return _stkUiApplication; }
}
Form Class
private void SubscribeToStkQuit()
{
UtilStk.StkUiApplication.OnQuit += StkQuit;
}
private void StkQuit()
{
MessageBox("TEST");
}
Yes, you can!
But it's better to use actions and functions, which are flexible in terms of parametrization (all of them are in System namespace).
Anyway, I've another suggestion: why don't you use event accessors? You can create one in your static class:
About actions and functions, these are delegates too, so you can use them everywhere as input parameters for any delegation.
Perhaps you can use the event accessor and do it in a .NET way, can't you?
If you subscribe to a static event with an instance method, then the instance will not be garbage collected until the static event is disposed (unless you unsubscribe).
This will cause a memory leak.
Beyond that, the problem with your code is that the signature of
ForceClose()
does not match_stkUiApplication.OnQuit
it needs to beForceClose(object sender, SomeKindOfEventArgs e)
It should be
UtilStk.SubscribeToStkQuit(forceClose => (s, e){ForceClose();});
EDIT:
The reference to your external app is static:
so it will live for the duration of your application. Adding an event handler to
passes a reference to a method on the instance of your form class. This reference will now be held for the life of your application, so it cannot be garbage collected.
To handle for this situation, either explicitly de-register (-=) the handler when the listening object is disposed, or handle static events with static handlers.
I mistakenly thought that you were describing web forms at first, which changes things a bit (you may only ever instantiate one
Form
), but the above holds true regardless. And it is good practice.To solve your current problem: You need to type the parameter passed to:
to be the type of
_stkUiApplication.OnQuit
Something like
Then you can do this: