How to raise an event on other instances of the same class - c#

I have a class with an EventHandler for TimeChanged. A couple of instances of this class are created. In one of the instances of the class, the time can be changed. I would like all instances to react to the event of changed time.
Example:
public class MainClass
{
public MainClass()
{
}
public event EventHandler TimeChanged;
private virtual void OnTimeChanged()
{
EventHandler handler = TimeChanged;
if(handler != null)
{
handler(this, eventArgs.Empty);
}
}
}
public class AnotherClass
{
public AnotherClass()
{
MainClass _mainClass = new MainClass();
}
private void OnLoaded()
{
_mainClass.TimeChanged += HandleTimeChanged;
}
private void HandleTimeChanged
{
//Some stuff happens with new time, etc.
}
}
public class TimeClass
{
MainClass _class = new MainClass();
TimeSpan _timeValue;
private void ChangeTime()
{
// This is where the _timeValue is changed
// All instances of MainClass, subscribed to TimeChanged event to be notified with the new value selected.
}
}
So, basically when I change the time in TimeClass, which contains an instance of MainClass, I want to fire the TimeChanged event and all instances of MainClass (like in AnotherClass) should respond to the TimeChanged event to which they subscribed.
Hope this explains the situation. Any suggestions are welcome. Thanks.

Related

How to raise the same event from different classes?

I have a class library that has a number of classes.
Any of these classes should be able to send a message (string) to the client at any point of time . I want to have a Generic Event that can be raised from a number of classes. I don't want a separate event for each class.
Something like this:
public class GenericEvent
{
// Here I have an event.
}
public class LibClass1
{
//Raise event here.
}
public class LibClass2
{
//Raise event here
}
public class Client
{
//Subscribe to the event here
}
Is this the right approach? If yes, how can it be achieved? The examples I looked up all have a separate event for each class.
It depends on what this event is and use cases, but one of the options is to use inheritance:
public class GenericEvent
{
// Here I have an event.
protected void RaiseEvent();
}
public class LibClass1 : GenericEvent
{
public voidDoSomethingAndRaiseEvent()
{
// ...
RaiseEvent();
}
}
This is how INotifiPropertyChanged is usually implemented.
If inheritance is impossible and you're using aggregation, LibClass1 and LibClass2 should act as some facade/decorator for GenericEvent: they must have their own event, which re-directs calls to GenericEvent's event and method(-s) to raise it:
public class GenericEvent
{
public event EventHandler SomeEvent;
// ...
}
public class LibClass1
{
private readonly GenericEvent _ge;
// ...
public event EventHandler SomeEvent
{
add { _ge.SomeEvent += value; }
remove { _ge.SomeEvent -= value; }
}
public void DoSomethingAndRaiseEvent()
{
// ...
SomeEvent?.Invoke(this, EventArgs.Emtpy);
}
}
public class MyEventArgs : EventArgs
{
// class members
}
public abstract class Lib
{
public event EventHandler ShapeChanged;
public virtual void OnShapeChanged(MyEventArgs e)
{
if (ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
public class LibClass1 : Lib
{
//Raise event here.
}
public class LibClass2 : Lib
{
//Raise event here
}
static void Main(string[] args)
{
LibClass1 lib1 = new LibClass1();
LibClass2 lib2 = new LibClass2();
lib1.ShapeChanged += Lib1_ShapeChanged;
lib2.ShapeChanged += Lib1_ShapeChanged;
lib1.OnShapeChanged(new MyEventArgs());
}
Here full example create an abstract class in which you have the event.
I would work with inheritance. For example:
public class ParentClass : Form
{
public ParentClass() {
this.FormClosed += sendString;
}
private void sendString(object sender, FormClosedEventArgs e)
{
throw new NotImplementedException();
}
}
public class GenericEvent : ParentClass { }
public class LibClass1 : ParentClass { }
public class LibClass2 : ParentClass { }
public class Client : ParentClass { }
Now all of you Clases have the event of the ParentClass.
I have another approach.
Derive all of your classes from one single base class. (of course any library do that, .net or MFC or Qt or java framework).
you have a single event "event 1" in base class. In that event1 handler, raise "event 2".
Subscribe all your child classes to the "event2" of parent class and handle your business in respective child classes.

C# Subscribing an Event

I have the following code with 3 different classes. I am trying to
Subscribe event from class B to method (event handler) defined in
class ControlSystem. All compiles fine, it works no problem but the event handler method is never triggered... What am I doing wrong?
namespace EventTest
{
public class ControlSystem : CrestronControlSystem
{
A myObject = new A();
public ControlSystem(): base()
{
Thread.MaxNumberOfUserThreads = 100;
// Subscribe Event
myObject.mySubObject.BEvent += HandleBEvent;
// Throw Event
myObject.mySubObject.ThrowEvent();
}
public override void InitializeSystem()
{
}
public void HandleBEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happend to {0}", sender);
}
}
public class A
{
public B mySubObject;
public A()
{
mySubObject = new B();
}
}
public class B
{
public EventHandler BEvent;
public B(){}
public void ThrowEvent()
{
EventHandler handler = BEvent;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
}
Real code links below (it works with Embeded system so you won't be able to compile it). Idea is to have button press to trigger an event which could
alarm other UIs that something happend to it.
http://ideone.com/NJz2Ek
Thanks
You are missing the event keyword.
public event EventHandler BEvent;
is what needs to be there.

How to make only farthest child receive shared event?

I have run into a bit of a design issue with my code.
I have a object that creates a child object (the child could then create another child, etc), and both objects subscribe to the same event.
But, I only want the most child object to receive the event.
Overview of what my project is:
I am creating a IVR system. When a user calls into the system, the user will have X menu choices. Based on what the user chooses they will have a sub menu of choices, and so on and so on. I am using State Machines for this. Every State Machine needs to "listen" for when the user presses a number on their phone. But only the current State Machine needs to process the entered number. Each State Machine can create a new State Machine to represent the sub menu.
Here is some sample code:
Base class:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
public event DoSomething myEvent;
private IObject foo;
public Base ()
{
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
if (myEvent != null)
{
myEvent(this, new EventArgs());
}
}
}
ObjectA:
class myObjectA : IObject
{
private Base theCallingObject;
private IObject child;
public myObjectA (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
public void CreateChild()
{
child = new myObjectB(theCallingObject);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectA");
}
}
ObjectB:
class myObjectB : IObject
{
private Base theCallingObject;
public myObjectB (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectB");
}
}
Now when I do this:
Base blah = new Base();
blah.SomeAction();
blah.EventFired();
I get message boxes for both A and B.
I need to implement Base so that only myObjectB gets the event.
I will have hundreds of myObject's so I need a implementation at the Base level and NOT the myObject level. Plus, handling it at the myObject level would still require the event to be fired causing performance issues if there are hundreds of objects.
One solution I have considered is when myObjectA creates the child, unsubscribe from the event, then resubscribe when we get back to the myObjectA level. However I feel something better could be done.
Anyone have any ideas?
Edit: Using payo's input I have come up with this:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
private IObject foo;
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
public Base ()
{
_myEventStorage = new List<DoSomething>();
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
_myEventStorage[0].Invoke(this, new EventArgs());
}
}
you would need to explicitly implement myEvent (add/remove) handlers and track the "farthest" independently of the registered observers. then you can send the notification to that single instance.
For events, each subscriber is queued up (put at end of list), a FIFO model. You want the most-child object to 'own' the event, not just subscribe and be part of some abstract list of other unknown objects.
I would provide a new model that represents what you are trying to do. This might be what Jason recommended: (he posted his answer as I was typing this out)
public class Base
{
private DoSomething _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage = value;
}
remove
{
_myEventStorage -= value;
}
}
...
public void EventFired()
{
if (_myEventStorage != null)
{
_myEventStorage(this, new ChainEventArgs());
}
}
}
This calls last ONLY. Another option (to add to this custom add/remove) would be to provide a derived EventArgs:
public class ChainEventArgs : EventArgs
{
public bool Handled { get; set; }
}
public delegate void DoSomething(object sender, ChainEventArgs data);
...
public event DoSomething myEvent
{
add
{
var temp = _myEventStorage;
_myEventStorage = null;
_myEventStorage += value;
_myEventStorage += temp; // now all are called, but FILO
}
remove
{
_myEventStorage -= value;
}
}
At this point, you can either check Handled on each IObject
void theCallingObject_myEvent(object sender, ChainEventArgs data)
{
if (data.Handled)
return;
if (I_want_to_block_parents)
data.Handled = true;
// else leave it false
}
Or, add some complexity to your Base class and stop calling up the chain (let's the children have no need to check Handled). I'll show the solution with a List<> of delegates, but some MulticaseDelegate casts and calls could do the same. I just feel the List<> code might be more readable/maintainable.
public class Base
{
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
...
public void EventFired()
{
var args = new ChainEventArgs();
foreach (var handler in _myEventStorage)
{
handler(this, args);
if (args.Handled)
break;
}
}
}

Passing EventHandler between several classes

I am creating a gui widget a dll library, a class that derives from a FORM (I thought about usercontrol but it doesn't have built in properties like Opacity and some more that i need).
Because I don't want to expose to the user of this control all the standard methods and propertis that this derived class will inherit, I've created a nothe class "middle-man" that should encapsulate and expose only the needed methos to the user of this dll.
The problem is exposing the events.
This is an abstract example:
class Class1
{
Class2 theClass2;
public Class1()
{
theClass2 = new Class2();
theClass2. += new EventHandler(theClass3_EventHandler);
theClass2.TriggerEvent();
}
void theClass3_EventHandler(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
class Class2
{
Class3 theClass3;
public Class2()
{
theClass3 = new Class3();
}
public void TriggerEvent()
{
theClass3.Trigger();
}
class Class3
{
public event EventHandler theEvent;
public void Trigger()
{
if (this.theEvent != null)
theEvent(this, new EventArgs());
}
}
}
public event EventHandler theEvent {
add {
SomeNestedClass.theEvent += value;
}
remove {
SomeNestedClass.theEvent -= value;
}
}
First of all, inheritance is a is-a relationship. That means that everything that a Form can do should all sub classes be able to do. Since this is not the case for you, you should not derive the form.
As for the events. You need to redefine them in your "middle-man" class. And in that class simply subscribe on the events from the form and trigger them in the handler methods.
public class MyCoolControl : Control
{
private Form _customForm;
public MyCoonControl()
{
_customForm.Clicked += (source, e) => Clicked(source,e);
}
public event EventHandler Clicked = delegate {};
}

how to implement on change notification on a object

I have a plain normal class, e.g.:
public class ObjectA
{
public string val {get;set;}
...
}
in another class, it holds an instance of ObjectA, e.g.:
public class ObjectB
{
private ObjectA objectA;
....
}
the instance "objectA" will be frequently changed.
i mean in ObjectB, some of the method will new and new instance of Object A and assign to "objectA"
is there a way to implement a trigger, whenever instance objectA is change, will allow me to do something, e.g.:
objectA += OnChanged_ObjectA
protected void OnOnChanged_ObjectA()
{
// do something
}
You can create a change event on ObjectA that you will fire for any of the changes you wish to track. This will allow you to subscribe to this event on any other object, including ObjectB.
In Object1.cs:
// Delegate type for the event handler
public delegate void MyEventHandler();
// Declare the event.
public event MyEventHandler MyEvent;
// In the properties or any place you what to notify of change:
if (MyEvent != null)
MyEvent();
And in Object2.cs you can subscribe:
objectA.MyEvent += OnChanged_ObjectA
protected void OnOnChanged_ObjectA()
{
// Action changes
}
How about :
INotifyPropertyChanged Interface
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
I had such problem recently, but unfortunately, I didn't find any another solution, but this:
public ObjectB
{
private ObjectA _objectA;
public ObjectA objectA
{
get
{
return _objectA;
}
set
{
if (value != _objectA)
{
_objectA = value;
RaiseObjectAChanged(/* sender, args */);
}
}
}
private RaiseObjectAChanged()
{
// raise event here
}
private OnObjectAChanged()
{
// event handler
}
}

Categories