Connecting an event handler in one class and disconnecting it in a different class.

  • Thread starter Thread starter SunshineGirl
  • Start date Start date
S

SunshineGirl

In my code, class A instanciates classes B and C.

I would like class B to connect an event handler to a method in class A, and
for class C to disconnect that event handler.

I think I've done too much thinking, and now I'm even more confused as to
how to accomplish this as when I started.

Any help will be appreciated.
 
Hi,

Thanks for posting. The following code is for your reference:

using System;

public delegate void ADelegate();

public class A
{
public static void Main(string[] args)
{
B b = new B();
ADelegate d = new ADelegate(AMethod);
b.AEvent += d;
C c = new C();
c.RemoveDelegateFromB(d, b);
}

public static void AMethod()
{
Console.WriteLine("A method");
}
}

public class B
{
public event ADelegate AEvent;
public void RaiseAEvent()
{
if (AEvent != null)
{
AEvent();
}
}
}

public class C
{
public void RemoveDelegateFromB(ADelegate d, B b)
{
b.AEvent -= d;
}
}

I hope this helps. If there is anything else I can help with, please feel
free to post here.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Assuming that ClassB and ClassC have a reference to ClassA then there should
be no Problem in doing this.

class ClassA
{
ClassB cl_B=null;
ClassC cl_C=null;
Panel pn_Panel=null
public ClassA()
{
pn_Panel = new Panel();
cl_B = new ClassB(this);
cl_C = new ClassC(this);
}
public void Dispose()
{
if (cl_C != null)
cl_C=null;
}
protected virtual void OnMouseDown(object
sender,System.Windows.Forms.MouseEventArgs e)
{
if (i_DragDrop == 0)
{
OnDragDrop(e.X,e.Y); // Do what must be done and check the results, set
i_DragDrop if something found
} // if (i_DragDrop == 0)
} // protected override void OnMouseDown(object
sender,System.Windows.Forms.MouseEventArgs e)
} // Class A

class ClassB
{
public ClassB(ClassA cl_A)
{
cl_A.pn_Panel.MouseDown += new
System.Windows.Forms.MouseEventHandler(cl_A.OnMouseDown);
}
} // ClassB
class ClassC
{
ClassA cl_A=null;
public ClassC(ClassA clA)
{
cl_A = clA;
}
public void Dispose()
{
if (cl_A != null)
cl_A.pn_Panel.MouseDown -= new
System.Windows.Forms.MouseEventHandler(cl_A.OnMouseDown);
}
} // ClassC

This should work.
This works in my Projects where a ClassA calls ClassB assuming that ClassB
will clean up what it has done in ClassA when closing.
Note : since ClassA is only needed in the Construction of ClassB here, it is
not saved to a Class Field as in ClassC.

Mark Johnson, Berlin Germany
(e-mail address removed)
 
Not quite.

Class A must hold the code for the event.
Class B must connect an event handler (+=), not raise the event.
Class C must disconnect the event handler (-=).

This is an already running application to which I'm trying to add
functionality. Class B uses Windows instrumentation to receive a
notification when the user launches an application. Class C uses Windows
instrumentation to receive a notification when the user terminates an
application. Class A instanciates both classes B and C. Classes B and C
don't know about each other.

The application currently monitors when the user has launched or terminated
applications. I'm trying to add the following functionality.

Whenever class B receives notification that Internet Explorer has launched,
it needs to connect the BeforeNavigate2 event handler to a method in class A
(so class B must do the += thing: ie.BeforeNavigate2 += new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(this.ie_BeforeNavigat
e2). Whenever class C receives notification that Internet Explorer has been
terminated, it needs to disconnect the BeforeNavigate2 event handler (so
class C must do the -= thing: ie.BeforeNavigate2 -= new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(this.ie_BeforeNavigat
e2).
 
Hello,

Thanks for your update.

I would like to ask a question. What is the object that exposes the event
"BeforeNavigate2" and how do you get a reference to it? If we can get the
reference (e.g. named "o") successfully, we can simply call
"o.BeforeNavigate2 += " in class B and "o.BeforeNavigate2 -= " in class C.

In addition, since the method for the event is defined in class A, we
cannot use "this" in class B and class C. If we define the method as
static, we can use "o.BeforeNavigate2 += new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(A.ie_BeforeNavigate2)
". If the method is non-static, we need to pass a reference to A into B or
simply create a new A object, so that the method can be accessed.

I hope this helps.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
The object that exposes the BeforeNavigate2 event is the Internet Explorer
ShellWindows interface.

Here is that part of the code that connects the event handler. This is from
a Windows app and it works. Now it must be in class B):
private static SHDocVw.ShellWindows shellWindows = new
SHDocVw.ShellWindowsClass();

foreach(SHDocVw.InternetExplorer ie in shellWindows)
ie.BeforeNavigate2 += new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(this.ie_BeforeNavigat
e2);

This is the event handler (that must be in class A):
public void ie_BeforeNavigate2(object pDisp , ref object url, ref object
Flags, ref object TargetFrameName, ref object PostData, ref object
Headers, ref bool Cancel)
{
MessageBox.Show("BeforeNavigate2: " + url.ToString());
}

Thank you for your help.
 
Here's how far I got. But it doesn't work. Class B never enters the foreach loop.

ClassA:
public static SHDocVw.ShellWindows shellWindows = null;

public void ie_BeforeNavigate2(object disp, ref object url, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel)
{
MessageBox.Show("BeforeNavigate2: " + url.ToString());
}



ClassB:
private ClassA classA = null;

in the constructor:
ClassA.shellWindows = new SHDocVw.ShellWindowsClass();
foreach(SHDocVw.InternetExplorer ie in ClassA.shellWindows)
ie.BeforeNavigate2 += new SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(classA.ie_BeforeNavigate2);



ClassC:
private ClassA classA = null;

in the constructor:
ClassA.shellWindows = new SHDocVw.ShellWindowsClass();
foreach(SHDocVw.InternetExplorer ie in ClassA.shellWindows)
ie.BeforeNavigate2 -= new SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(classA.ie_BeforeNavigate2);
 
Hello,

Thanks for your update. Let's try the following:

ClassA:
public static SHDocVw.ShellWindows shellWindows = new
SHDocVw.ShellWindowsClass();

public static void ie_BeforeNavigate2(object disp, ref object url, ref
object flags, ref object targetFrameName, ref object postData, ref object
headers, ref bool cancel)
{
MessageBox.Show("BeforeNavigate2: " + url.ToString());
}

ClassB:

in the constructor

foreach(SHDocVw.InternetExplorer ie in ClassA.shellWindows)
ie.BeforeNavigate2 += new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(ClassA.ie_BeforeNavig
ate2);

ClassC:

in the constructor

foreach(SHDocVw.InternetExplorer ie in ClassA.shellWindows)
ie.BeforeNavigate2 -= new
SHDocVw.DWebBrowserEvents2_BeforeNavigate2EventHandler(ClassA.ie_BeforeNavig
ate2);

Since the "shellWindows" is a static member, we can access it from both
ClassB and ClassC. We only need to "new" it once in ClassA. I have not
tested the code with IE. But from C# language's perspective, it should
work. I hope this helps.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Thanks. That worked in a Windows application. However, I can't get it to
work inside a Windows service, which is what I want. I get the following
exception when I run the line "shellWindows = new
SHDocVw.ShellWindowsClass();":

COM object with CLSID {9BA05972-F6A8-11CF-A442-00A0C90A8F39} is either not
valid or not registered.

I know that this CLSID belongs to ShellWindows.

Any ideas?

Thanks again.
 
Hello,

I am afraid that we cannot achieve this in a .Net Windows Service
application. .Net Windows Services are running without any user interface.
They are not intended to interact with any user's desktop. In fact, they
are in separate sessions. You may refer to the following article for
detailed information:

Introduction to Windows Service Applications
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/
vbconintroductiontontserviceapplications.asp

It is mentioned that "The Windows Service classes supported by the .NET
Framework do not support interaction with interactive stations, that is,
the logged-on user. The .NET Framework also does not include classes that
represent stations and desktops. If your Windows Service must interact with
other stations, you will need to access the unmanaged Windows API. For more
information, see Window Stations and Desktops in the Platform SDK
documentation."

I hope this helps.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Back
Top