Goal: Have a singleton publish events and allow any class to subscribe/listen to those events
Problem: I cannot figure out how to do this. The code below is illegal but it purveys what I'm trying to do
TransmitManager Class - Publisher
//Singleton
public sealed class TransmitManager
{
delegate void TransmitManagerEventHandler(object sender);
public static event TransmitManagerEventHandler OnTrafficSendingActive;
public static event TransmitManagerEventHandler OnTrafficSendingInactive;
private static TransmitManager instance = new TransmitManager();
//Singleton
private TransmitManager()
{
}
public static TransmitManager getInstance()
{
return instance;
}
public void Send()
{
//Invoke Event
if (OnTrafficSendingActive != null)
OnTrafficSendingActive(this);
//Code connects & sends data
//Invoke idle event
if (OnTrafficSendingInactive != null)
OnTrafficSendingInactive(this);
}
}
Test Class - Event Subscriber
public class Test
{
TrasnmitManager tm = TransmitManager.getInstance();
public Test()
{
//I can't do this below. What should my access level be to able to do this??
tm.OnTrafficSendingActive += new TransmitManagerEventHandler(sendActiveMethod);
}
public void sendActiveMethod(object sender)
{
//do stuff to notify Test class a "send" event happend
}
}
You shouldn't need to make the events static.
public event TransmitManagerEventHandler OnTrafficSendingActive;
public event TransmitManagerEventHandler OnTrafficSendingInactive;
Either your events have to be instance members or you have to address them as static.
TransmitManager.OnTrafficSendingActive +=...
OR
public event TransmitManagerEventHandler OnTrafficSendingActive;
...
TransmitManager.Instance.OnTrafficSendingActive+=...
Also: use EventHandler as your event delegate. Consider making a custom arguments class and pass the status to just one event instead of multiple events. This will let you pass status messages as well.
Related
Suppose I have two classes - one that is provided to me (but suppose I am not allowed to change it as it is maintained by someone else), and one that I control and can change.
// Class A is provided to me by someone else, and suppose I can't modify it
public class A
{
public A()
{
...
}
public void DoSomethingInA()
{
...
}
}
// Class B is what I control
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
// *** HERE IS WHERE I NEED HELP
// NEED TO WRITE AN EVENT / EVENT HANDLER, WITH / WITHOUT REFLECTION
// THAT RUNS DoSomethingInB WHENEVER MyClassAInstance's DoSomethingInA
// METHOD IS CALLED (AND COMPLETED)
}
public void DoSomethingInB()
{
...
}
}
How can I define a Event / EventHandler in class B that kicks off its DoSomethingInB method whenever the class A instance MyClassAInstance's method DoSomethingInA is called (and completed).
I tried lot of options, but none seem to work.
For instance, I tried:
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
var eventInfo = GetType().GetEvent("MyEvent");
var methodInfo = myClassAInstance.GetType().GetMethod("DoSomethingInA");
Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, myClassAInstance, methodInfo);
eventInfo.AddEventHandler(this, handler);
MyEvent += DoSomethingInB;
}
public event EventHandler MyEvent;
public void DoSomethingInB()
{
...
}
}
But this doesn't work.
Any suggestions or help would be greatly appreciated.
In my application I have a interface IEncoder that is having event EncoderCaller.
public interface IEncoder
{
event EncoderCaller EncoderCalled;
}
public delegate void EncoderCaller(object Source, EventArgs args);
public class Video
{
public string Title { get; set; }
}
public class VideoEventArgs : EventArgs
{
public Video xVideo { get; set; }
}
public class DetectionAction : IEncoder
{
public event EncoderCaller EncoderCalled;
public void Encode(Video video)
{
//some logic to encode video
OnVideoEncoded();
}
protected virtual void OnVideoEncoded()
{
if (EncoderCalled != null)
EncoderCalled(this, EventArgs.Empty);
}
}
public class Client1: IEncoder
{
}
I need some mechanism by which I should be able to share a contract, if that is implemented by any client then that event will trigger event in my class DetectionAction .
Can someone tell me, Am I doing right thing.
How it can be done?
If you have two classes in the same process, you could consider explicitly chain events like this:
public class Client1 : IEncoder
{
public event EncoderCaller EncoderCalled;
public Client1(IEncoder anotherEncoder)
{
// Listen to event raised on another instance and raise event on this instance.
anotherEncoder.EncoderCalled += OnAnotherEncoderCalled;
}
private void OnAnotherEncoderCalled(object source, EventArgs args)
{
if (EncoderCalled != null)
EncoderCalled(this, EventArgs.Empty);
}
}
In this case, for example, anotherEncoder is DetectionAction.
However, if you are seeking solution for sharing events between two different applications running in different processes, you might be looking at inter-process communication, like this post:
Listen for events in another application
And the above example code still works, but the IEncoder in this case is an implementation with IPC support, for example a message queue listener which raises the event on message received.
I am having some issues with handling an event that I am raising in a separate DLL in a separate exe. I have a class that subscribes to the event in another DLL. When I raise the event, by the time I get to the event handling, the event handler is null since the object that subscribed to it exists in separate call stack. Is there a clean way to handle something like this?
Public class B is in another dll on another executable (same solution) than Class A.
public static class CustomEvent
{
public static event EventHandler<CustomEventArgs> eventHandler;
public static void Raise(CustomEventArgs args)
{
// When class B raises the event. The eventHandler here is null.
// Meaning it doesn't know that Class A has subscribed to the event.
EventHandler<CutomEventArgs> handler = eventHandler;
if(handler != null)
{
eventHandler(typeof(CustomEvent), args);
}
}
}
public class A
{
public class A ()
{
CustomEvent.eventHandler += HandleEvent;
}
public class B
{
public void Function()
{
CustomEvent.Raise(new CustomEventArgs());
}
}
This has been asked probably many times, but looking through all the other questions I still was not able to solve my issue. I want to update a Datagridview on a form using an update function on this form. The Update function is called by a subscriber.
Overview:
static class MainClass
{
static void Main()
{
// The Main form is called.
MainForm = new frmMain();
Application.Run(MainForm);
//Application.Run(new frmMain());
}
}
A Delegate
public delegate void Delagate_UpdateDataView();
The subscriber that subscribed to publisher that fires an event every 500 ms.
public class SubscriberFrmMain
{
// Constructor
public SubscriberFrmMain()
{
}
// Subscribe to the Publisher
public void Subscribe(PublisherTimedEvent mUpdateHMIData)
{
//attach listener class method to publisher class delegate object
mUpdateHMIData.TickUpdateHMIData += UpdateHMIData;
}
// The Event, fired when the Publisher raises an event.
private void UpdateHMIData(PublisherTimedEvent mUpdateHMIData,EventArgs e)
// Calling the Update function on the Form MainForm.
{
MainClass.MainForm.Process_UpdateDataView(new
Delagate_UpdateDataView(MainClass.MainForm.UpdateDataView));
}
}
The Update function in the Form
public void Process_UpdateDataView(Delagate_UpdateDataView update)
{
update();
}
public void UpdateDataView()
{
try
{
TagTableAdapter.Fill(uDataSet.PLC_Tag);
}
catch
{
}
}
Updating the TagTableAdapter manually works without any problem. Updating using the subscriber does nothing.
Probably there are easier ways to achieve this but I would like to use this type of construction also for other parts of the program.
Thanks for your suggestions.
Event's can only be risen from inside the class. If you could do that it would defeat the purpose of events.You can subscribe to this event from other class tho.
public event EventHandler someEvent;
EventContainer obj = new EventContainer();
obj.someEvent += handler;
where handler is a method according to the signature of someEvent. One is able to subscribe to the event from the outside just fine, but it can only be risen from inside the class defining it.
Lets say I have the below code. What is the difference between assigning the actions directly and subscribing to an event?
//Action directly assigned
public class ClassA
{
public Action<string> OnAdd;
private void SomethingHappened()
{
OnAdd("It Happened");
}
}
public class ClassB
{
public ClassB()
{
var myClass = new ClassA();
myClass.OnAdd = Add;
}
private void Add(string Input)
{
//do something
}
}
//Event handlers
public class ClassA
{
public event Action<string> OnAdd;
private void SomethingHappened()
{
if (OnAdd != null)
OnAdd("It Happened"); //Should it be OnAdd.Invoke("It Happened") ???????
}
}
public class ClassB
{
public ClassB()
{
var myClass = new ClassA();
myClass.OnAdd += Add;
}
private void Add(string Input)
{
//do something
}
}
(As an aside, it's hard to explain things when you've used the same type names twice.)
When you use a public field, clients can not only subscribe to events - they can also completely remove other event handlers by assigning instead of adding:
myClass.OnAdd = Add;
They can also invoke the handler directly:
myClass.OnAdd("foo");
Both of these violate the normal pub/sub pattern, where the various subscribers are isolated from one another. Subscribers don't get to overwrite each other's subscriptions (only add or remove their own) and they don't get to raise the event themselves.
For more on events and delegates, see my article on the topic.
You can assign more than one delegates to one event (thus the += operator).
An Event acts like a wrapper around a Delegate to offer protection from reassigning/removing as John has pointed out. I found this quite a good read.