Here are 3 C# classes :
class StartClass
{
event StartEvent;
// some code
class MidClass
{
private StartClass _startClass;
public MidClass (StartClass startClass)
{
_startClass = startClass;
}
// some code
class EndClass
{
private MidClass _midClass;
public EndClass (MidClass midClass)
{
_midClass = midClass;
}
// some code
public void OnStartEvent ()
{
// code to be executed on StartEvent called
}
What's best way if you want to attach EndClass.OnStartEvent listener to StartClass.StartEvent event ?
I think the best way would be to create a MidClass.StartEvent property referencing StartClass.StartEvent event in order to be able to attach the listener in EndClass doing _midClass.StartEvent =+ OnStartEvent;. Am I right ? How to attach StartClass.StartEvent to MidClass.StartEvent ?
In C# an event is much like a property. It is a wrapper for a delegate. Usually we are using auto-implemented events. But we can expand them. Properties have get and set accessors. Events have add and remove accessors.
class MidClass
{
private readonly StartClass _startClass;
public MidClass (StartClass startClass)
{
_startClass = startClass;
}
public event EventHandler StartEvent
{
add => _startClass.StartEvent += value;
remove => _startClass.StartEvent -= value;
}
}
Here, we create a StartEvent in MidClass that is a wrapper for the corresponding event in StartClass. StartClass.StartEvent must be public.
The advantage of this approach is that an event handler subscribing to MidClass.StartEvent will directly be attached to StartClass.StartEvent, with no intermediate call occurring when the event is risen.
One word to naming. Methods named OnEventName are usually used to raise events, while methods named PublisherName_EventName are used for event handlers.
class StartClass
{
public event EventHandler StartEvent;
private virtual void OnStartEvent()
{
StartEvent?Invoke(this, EventArgs.Empty);
}
}
class EndClass
{
private MidClass _midClass;
public EndClass (MidClass midClass)
{
_midClass = midClass;
_midClass.StartEvent += MidClass_StartEvent;
}
private void MidClass_StartEvent (object sender, EventArgs e)
{
// Code to be executed when StartEvent is triggered
}
}
I think the best way would be to create a MidClass.StartEvent property referencing StartClass.StartEvent event in order to be able to attach the listener in EndClass doing _midClass.StartEvent =+ OnStartEvent;. Am I right?
If you want to keep the reference to StartClass a private implementation detail of MidClass: Yes, implementing a "proxy" StartEvent in MidClass is the right way to do it.
How to attach StartClass.StartEvent to MidClass.StartEvent ?
By attaching a listener to _startClass.StartEvent which just raises the corresponding event in MidClass:
class MidClass
{
public event EventHandler StartEvent;
private readonly StartClass _startClass;
public MidClass(StartClass startClass)
{
_startClass = startClass;
_startClass.StartEvent += (sender, e) => this.StartEvent?.Invoke(this, e);
}
...
}
Note that I also added the readonly modifier to _startClass: If the value of _startClass changes during the lifetime of MidClass, you need to detach your event handler from the old reference and attach it to the new reference.
Related
I'm working with an interface IEventLogWatcher, its implementation EventLogWatcherWrapper, and a class that uses it all Subscriber. The issue I'm having revolves around assigning a delegate function to the EventHandler inside EventLogWatcherWrapper. My goal is to have the ReadEventLog() function get called when the EventRecordWritten event gets raised:
IEventLogWatcher.cs
public interface IEventLogWatcher : IDisposable {
event EventHandler<IEventRecordWrittenEventArgs> EventRecordWritten;
}
EventLogWatcherWrapper.cs
class EventLogWatcherWrapper : IEventLogWatcher {
private EventLogWatcher eventLogWatcher {get; set;}
public event EventHandler<IEventRecordWrittenEventArgs> WrapperEventRecordWritten;
public EventLogWatcherWrapper(EventLogQuery eventQuery){
eventLogWatcher = new EventLogWatcher(eventQuery);
}
event EventHandler<IEventRecordWrittenEventARgs> IEventLogWatcher.EventRecordWritten
{
add => WrapperEventRecordWritten += value;
remove => WrapperEventRecordWritten -= value;
}
}
Subscriber.cs
public class Subscriber{
IEventLogWatcher _watcher = new EventLogWatcherWrapper(someEventQuery);
public void someFunction(){
...
_watcher.EventRecordWritten += ReadEventLog;
// A breakpoint immediately after this statement reveals that _watcher.EventRecordWritten is still null even after this assignment
}
public void ReadEventLog(object obj, IEventRecordWrittenEventArgs arg){
// I expect this to get called when the EventRecordWritten event gets raised.
// This never gets called.
}
}
For some reason when I assign _watcher.EventRecordWritten += ReadEventLog;, I still see null for the EventRecordWritten field of _watcher so I suspect I am doing something wrong in EventLogWatcherWrapper in implementing the interface?
I wanted to ask if this is Event possible in C#. I have not much worked with Events till now.
Say I have a class A which subscribed to a FormClosing Event of a form:
public class A
{
private void f_FormClosed(object sender, FormClosedEventArgs e)
{
//Now here a public Event should be called
}
}
Now there I want a public Event to be called. Let's say now I have another class B which has a certain method.
public class B
{
public void DoSomething()
{
}
}
Now what I want to do:
A Form gets closed so class A is getting notified. There, a public Event gets triggered (which is somewhere in a public class). I want to subscribe my method in class B to this Event so it gets called when that happens. Is this possible? And how is the syntax? I haven't found something useful till now.
Edit: I can't create an instance of class B directly from class A.
Its possible .
Create a new event in A.
Raise the event within the eventhandler f_FormClosed
Subscribe to this event in B.
Within the eventhandler in B call the method DoSomething
For the syntax part you could check MSDN
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
// A class that works just like ArrayList, but sends event
// notifications whenever the list changes.
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
//you raise the event here.
Changed(this, e);
}
}
Now in your other class do something like this
class EventListener
{
private ListWithChangedEvent List;
public EventListener(ListWithChangedEvent list)
{
List = list;
// Add "ListChanged" to the Changed event on "List".
//This is how we subscribe to the event created in ListWithChangedEvent class
List.Changed += new ChangedEventHandler(ListChanged);
}
// This will be called whenever the list changes.
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}
}
Interface-Events can be Implemented explicit. For example we are able to pass
delegates to another Event.
Here the TestHandler-Event is wrapped (not sure if its the right term) by the SomeHandler-Event to Implement the ISomeHandleable-Interface.
public delegate void HandlerDelegate();
public interface ISomeHandleable
{
event HandlerDelegate SomeHandler;
}
public class Test : ISomeHandleable
{
event HandlerDelegate ISomeHandleable.SomeHandler
{
add { TestHandler += value; }
remove { TestHandler -= value; }
}
public event HandlerDelegate TestHandler;
public void Fire() => TestHandler?.Invoke();
}
I have just recently seen, that we are also able to Implement ISomeHandleable.SomeHandleras follows:
event HandlerDelegate ISomeHandleable.SomeHandler
{
add { }
remove { }
}
But I have not yet found any documentation and possible usecases to this, and I also dont understand what it does.
I only know, delegates can still be added to ISomeHandleable.SomeHandler but the Event cannot be invoked by the Class Test anymore.
But as you can define Events with empty Accessors, what does it do and how is it meant to be used?
I have a class that has an event that's suppose to fire everytime one of it's property changes.
public event EventHandler StructureChanged;
protected virtual void NotifyStructureChanged(EventArgs e)
{
if (StructureChanged != null)
{
StructureChanged(this, e);
}
}
I include NotifyStructureChanged(new EventArgs()); in my set statement in my properties.
whenever it calls the method the StructureChangedis always null. My class is a private member in a custom usercontrol and the class event is registered in the constructor of the usercontrol like so
_pt.StructureChanged += _pt_StructureChanged;
and handled here
void _pt_StructureChanged(object sender, EventArgs e)
{
UpdateControl();
}
What I have so far is a custom class with an event that's a private member of a custom user control. I register my class event in the custom usercontrol. Whenever the class property changes, I update my control to reflect the changes in the class.
What am I doing wrong here? I have a button on my usercontrol and am able to register that event, why can't I register my class event?
If StructureChanged is null than you attach event handler after event was fired (or you are detaching handler somewhere).
Also don't pass EventArgs - its just useless dummy parameter.
public event EventHandler StructureChanged;
protected virtual void OnStructureChanged()
{
if (StructureChanged != null)
StructureChanged(this, EventArgs.Empty);
}
And call this method in setter:
public Foo Bar
{
get { return _bar; }
set {
if (_bar == value)
return;
_bar = value;
OnStructureChanged();
}
}
I have some C# code that updates some properties of an object. I have an event handler defined to help me respond when the update process is done. Unfortunately, I've learned that this event is getting fired multiple times. I suspect this is happening because the event handler is being set at the wrong time. Currently, it is being set like the following:
myObject.Update_Succeeded += new EventHandler(myObject_Update_Succeeded);
Due to the complexity of the code, I'm having a difficult time of tracking down where it should be set. I would like to only set the event handler it hasn't been previously set. Because of this, I want to do something like this:
ClearEventHandlers(myObject);
or
myObject.Update_Succeeded = null;
myObject.Update_Succeeded += new EventHandler(myObject_Update_Succeeded);
Is there a way to accomplish what I'm trying?
Thank you!
Yes, you can customize the add/remove accessors of your event. This article describes these accessors. But you can do something like:
class MyClass
{
private EventHandler _myEvent;
public event EventHandler MyEvent
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_myEvent = (EventHandler)Delegate.Combine(_myEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_myEvent = (EventHandler)Delegate.Remove(_myEvent, value);
}
}
public void ClearMyEvent() {
_myEvent = null;
}
...
}
You should be able to remove a handler using the subtract operator like below
myObject.Update_Succeeded -= new EventHandler(myObject_Update_Succeeded);
Or check this out for a way to remove all event handler if you are in doubt
How to remove all event handlers from a control
Proper way should be to detach the handler from each event after you no longer use it:
public class MyObjectListener
{
private readonly MyObject _object;
public class MyObjectListener(MyObject obj)
{
_object = obj;
Attach();
}
// adds event handlers
private void Attach()
{
obj.UpdateSucceeded += UpdateSuceededHandler;
obj.UpdateFailed += UpdateFailedHandler;
}
// removes event handlers
private void Detach()
{
obj.UpdateSucceeded -= UpdateSuceededHandler;
obj.UpdateFailed -= UpdateFailedHandler;
}
...
}
The only thing you need to decide is where to call the Detach method. For example, you can call it in the handler itself:
private void UpdateSuceededHandler(object sender, Data args)
{
Detach();
// do something when it succeeds
}
private void UpdateFailedHandler(object sender, Data args)
{
Detach();
// do something when it fails
}
Or, you could allow users of MyObjectListener to tell it that it no longer needs to listen to the attached object:
public void StopListening()
{
Detach();
}
An object which raises an event should not allow its listeners to modify the event invocation list. Each event listener should subscribe or unsubscribe its own event handlers only.
You better set event handler on the initialization of your object i.e. in your Constructor.