Having trouble changing event handler - c#

It's for my irc bot, and I am trying to change the message receiver event to be linked to the method in my other class.
private static void client_Connected(object sender, EventArgs e)
{
gamebot.LocalUser.JoinedChannel += LocalUser_JoinedChannel;
gamebot.LocalUser.MessageReceived += LocalUser_MessageReceived;
}
// private static void newmessage(object sender, IrcChannelEventArgs e)
// {
// e.Channel.MessageReceived += Hangman.MessageReceivedHangman;
// }
private static void LocalUser_JoinedChannel(object sender, IrcChannelEventArgs e)
{
e.Channel.MessageReceived += Channel_MessageReceived;
Console.WriteLine("Joined " + e.Channel + "\n");
}
Just not sure how to get the channeleventargs outside of a method, so I can change the event. The commented method shows sort of what i need.
public static void MessageReceivedHangman(object sender, IrcMessageEventArgs e)
{
That is the method in a different class i would like to have execute when a message is received.
Thanks for the help and sorry if this is a really stupid question I'm pretty new to all of this still.

It's hard to know what would be best here, as you have provided so little context. All we really know is that you have one class (call it class A) handling specific events, and another class (call it class B) that wants to be able to handle events the first class already knows about.
Based on that, there are at least a couple of possibilities that might work for you.
Option #1:
Expose the "joined" event so that the second class can receive the same notifications and subscribe to the channel's event:
class JoinedChannelEventArgs : EventArgs
{
public Channel Channel { get; private set; }
public JoinedChannelEventArgs(Channel channel) { Channel = channel; }
}
class A
{
public static event EventHandler<JoinedChannelEventArgs> JoinedChannel;
private static void LocalUser_JoinedChannel(object sender, IrcChannelEventArgs e)
{
e.Channel.MessageReceived += Channel_MessageReceived;
Console.WriteLine("Joined " + e.Channel + "\n");
EventHandler<JoinedChannelEventArgs> handler = JoinedChannel;
if (handler != null)
{
handler(null, new JoinedChannelEventArgs(e.Channel);
}
}
}
class B
{
static void SomeMethod()
{
A.JoinedChannel += A_JoinedChannel;
}
private static void A_JoinedChannel(object sender, JoinedChannelEventArgs e)
{
e.Channel += MessageReceivedHangman;
}
}
Option #2:
Expose the "message received" event instead:
class A
{
public static event EventHandler<IrcMessageEventArgs> AnyChannelMessageReceived;
public static void Channel_MessageReceived(object sender, IrcMessageEventArgs e)
{
// Whatever other code you had here, would remain
EventHandler<IrcMessageEventArgs> handler = AnyChannelMessageReceived;
if (handler != null)
{
handler(null, e);
}
}
}
class B
{
static void SomeMethod()
{
A.AnyChannelMessageReceived += MessageReceivedHangman;
}
}
It's not clear from your post whether having the sender of the original event is important. If it is, then IMHO Option #1 is better, as it provides direct access to the event. However, you could modify Option #2 so that it passed sender to the handler (in Channel_MessageReceived()), instead of the null that's in the example (the null is more idiomatic for a static event, but not mandatory).
If neither of those options work for you, please provide better context. See https://stackoverflow.com/help/mcve and https://stackoverflow.com/help/how-to-ask.

Related

Passing events between threads run from separate class C#

I'm struggling to pass data between a thread started in a separate class from my main form. I believe (I could be wrong) that I should use an event. The problem I have is my subscribers are always null as I call the BluetoothScan class and start the thread before the event is subscribed to:
BluetoothScan bluetoothScan = new BluetoothScan(this);
bluetoothScan.BluetoothDeviceDiscovered += OnBluetoothDeviceDiscovered;
How do I subscribe to the event before starting the thread?
I have my Main Form:
using System;
using System.Windows.Forms;
//https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.invoke?view=net-5.0#System_Windows_Forms_Control_Invoke_System_Delegate_System_Object___
namespace YieldMonitor
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
}
private void BtnConnectBT_Click(object sender, EventArgs e)
{
//Start looking for the yield monitor device.
BluetoothScan bluetoothScan = new BluetoothScan(this);
bluetoothScan.BluetoothDeviceDiscovered += OnBluetoothDeviceDiscovered;
}
static void OnBluetoothDeviceDiscovered(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Message recieved from event");
}
}
}
My class that looks for bluetooth devices and if the right one is found should fire the event:
using InTheHand.Net.Sockets;
using System;
using System.Linq;
namespace YieldMonitor
{
class BluetoothScan
{
public event EventHandler BluetoothDeviceDiscovered;
public BluetoothScan(MainForm mainForm)
{
System.Diagnostics.Debug.WriteLine("Starting BluetoothScan Class");
Run();
}
public void Run()
{
System.Diagnostics.Debug.WriteLine("Running BluetoothScan Class");
string myDeviceName;
ulong myDeviceAddress;
BluetoothClient btClient = new BluetoothClient();
BluetoothDeviceInfo[] btDevices = btClient.DiscoverDevices().ToArray();
foreach (BluetoothDeviceInfo d in btDevices)
{
System.Diagnostics.Debug.WriteLine(d.DeviceName);
System.Diagnostics.Debug.WriteLine(d.DeviceAddress);
//have we found the device we are looking for?
if (d.DeviceName == "DSD TECH HC-05")
{
myDeviceName = d.DeviceName;
myDeviceAddress = d.DeviceAddress;
//Send out found adapter to the next stage
OnBluetoothScanned(EventArgs.Empty);
break;
}
}
}
protected virtual void OnBluetoothScanned(EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Running OnBlueToothScanned");
EventHandler handler = BluetoothDeviceDiscovered;
if (handler != null)// we have a subscriber to our event
{
System.Diagnostics.Debug.WriteLine("BluetoothScanned is Not empty");
handler(this, e);
}
else
{
System.Diagnostics.Debug.WriteLine("BluetoothScanned is Empty");
}
}
}
}
EDIT
I've found some nice solutions using Tasks where I need to update a label once a task is completed ie.
bool myDevicePaired = false;
var eventDevicePaired = new Progress<bool>(boDevicePaired => myDevicePaired = boDevicePaired);
await Task.Factory.StartNew(() => BluetoothPair.Run(myDeviceAddress, eventDevicePaired), TaskCreationOptions.LongRunning);
//Register the device is paired with the UI
if (myDevicePaired)
{
BtnConnectBT.Text = "Disconnect?";
}
Which is working well for Tasks that have an end that I am waiting for example waiting for a bluetooth device to connect.
But I'm beginning to pull my hair out with System.InvalidOperationException: 'Cross-thread operation not valid: Control 'tbInfo' accessed from a thread other than the thread it was created on.' error when trying to update a form text box.
Example:
in my MainForm Class:
I create what I've called an Event Reciever...
private void BluetoothSocketEventReciever(object sender, EventArgs e)
{
Debug.WriteLine("Event!!!"); //writes data to debug fine
tbInfo.AppendText("Event!!!!"); //causing error
}
I create a task to read from the device...
private void ReadDataFromDevice(UInt64 myDeviceAddress)
{
BluetoothSocket bluetoothSocket = new BluetoothSocket(myDeviceAddress);
bluetoothSocket.BluetoothDataRecieved += BluetoothSocketEventReciever;
Task.Factory.StartNew(() => bluetoothSocket.Run(), TaskCreationOptions.LongRunning);
}
In my BluetoothSocket class I have an endless while loop which will be reading data from a socket (hopefully) At the moment its just creating an empty EventArgs to trigger the Event every second:
namespace YieldMonitor
{
class BluetoothSocket
{
ulong myDeviceAddress;
public event EventHandler BluetoothDataRecieved;
public BluetoothSocket (ulong deviceAddress)
{
myDeviceAddress = deviceAddress;
}
public void Run()
{
System.Diagnostics.Debug.WriteLine("Were in BluetoothSocket ... Address: " + myDeviceAddress);
while (true)
{
Thread.Sleep(1000);
Debug.WriteLine("In BluetoothSocket - Address = " + myDeviceAddress);
OnBluetoothDataRecieved(EventArgs.Empty);
}
}
protected virtual void OnBluetoothDataRecieved(EventArgs e)
{
EventHandler handler = BluetoothDataRecieved;
if (handler != null)
{
handler(this, e);
} else
{
//No subscribers
}
}
}
}
I'm sure I'm missing something simple here but how can I pass the data from the endless loop to the text box on the main form?
EDIT
Think I've just sorted it.
private void BluetoothSocketEventReciever(object sender, EventArgs e)
{
Debug.WriteLine("Event!!!");
tbInfo.Invoke((Action)delegate
{
tbInfo.AppendText("Event!!!");
});
//tbInfo.AppendText("Event!!!!");
}
Is this the correct way to do it?
You can Pass the event handler as a parameter on the constructor
public event EventHandler BluetoothDeviceDiscovered;
public BluetoothScan(MainForm mainForm, EventHandler bluetoothDeviceDiscovered)
{
System.Diagnostics.Debug.WriteLine("Starting BluetoothScan Class");
BluetoothDeviceDiscovered += bluetoothDeviceDiscovered
Run();
}
Personally, i'm not so fun of calling method on constructor. It can be source of bugs or performance issues
Constructor
In class-based object-oriented programming, a constructor
(abbreviation: ctor) is a special type of subroutine called to create
an object. It prepares the new object for use, often accepting
arguments that the constructor uses to set required member variables.
You can pass eventhandler as parameter and call Run later

Why is subscribed event always null?

I declare a subscription to event in:
public class MainClass
{
public void btndel_bar_Click(object sender, RoutedEventArgs e)
{
SomeClass sc = new SomeClass();
sc.FieldUpdate += new SomeClass.FieldUpdateHandler(sc_FieldUpdate);
}
void sc_FieldUpdate(object sender, ValueEventArgs e)
{
MessageBox.Show(e.Smth_property);
}
}
And here is I want to listen event:
public class Someclass
{
public delegate void FieldUpdateHandler(object sender, ValueEventArgs e);
public event FieldUpdateHandler FieldUpdate;
void Somemethod()
{
string str = "Steel";
ValueEventArgs args = new ValueEventArgs(str);
FieldUpdate(this, args);
}
}
A class which carries data:
public class ValueEventArgs : EventArgs
{
private string smth;
public ValueEventArgs(string smth)
{
this.smth = smth;
}
public string Smth_property
{
get { return smth; }
}
}
I always have FieldUpdate=null. How to solve it?
You're calling Somemethod() in the constructor, before the calling code gets a chance to add the event handler.
Therefore, the event is still null.
The moment you create the object of SomeClass your event would get reinitialized.
Make your event a static so that multiple objects of SomeClass would share it
public static event FieldUpdateHandler FieldUpdate;
I've read articles about delegates and events and after reading I always I thought to make all operations again. I did all over again and it works! Consequently I done something wrong when I did at the beginning of.

simple event c#

I have two classes, and i have to make an event to communicate between these classes.
Class a
{
public delegate void delegat(int a);
public event delegat exit;
...
private void a_FormClosed(object sender, FormClosedEventArgs e)
{
// My event named exit should run here, but I get exception!
exit(100);
}
}
Class b
{
a instance=new a();
a.exit+=new a.delegat(my_fun);
...
private void my_fun(int x)
{
if(x==100)
do_smth;
...
}
}
But the thing is that i get exception: "object reference not set to an instance of an object".
I can't understand what Am I doing wrong? Where should I make a new instance of this?
Thanks for help!
You are trying to assign the exit event on the class itself and not the instance e.g.
a.exit += ...
Should be:
instance.exit += ...
You also aren't checking whether your exit event has been assigned before attempting to fire it. There are other issues which you haven't taken into consideration like race conditions.
Here is a general example of a relatively safe way of handling events e.g.
public class A
{
public delegate void ExitHandler(object sender, int a);
public event ExitHandler Exit;
...
private void a_FormClosed(object sender, FormClosedEventArgs e)
{
OnExit(100);
}
protected virtual void OnExit(int a)
{
// take a reference to the event (incase it changes)
var handler = Exit;
if (handler != null)
{
handler(this, a);
}
}
}
public class B
{
private A _a;
public B()
{
_a = new A();
_a.Exit += (sender, value) => my_fun(value);
}
private void my_fun(int x)
{
if(x==100)
do_smth;
...
}
}
I would change "class a" code for calling the event to as follows:
Class a
{
public delegate void delegat(int a);
public event delegat exit;
...
private void a_FormClosed(object sender, FormClosedEventArgs e)
{
if (this.exit != null) // just in case a_FormClosed fires before assigning the event
exit(100);//here should run my event named exit but i get exception!
}
}
Verify if there is any subscriber exist to your event before raising it:
if (exit != null)
exit(100);
Another option - subscribing dummy event handler when you are defining event in class A:
public event delegat exit = (_) => { };
Also use PascalCase naming for types, events and methods. And there is predefined delegate in .NET which receives one argument and returns void: Action<T>
Try this
namespace foo
{
public delegate void delegat(int a);
Class a
{
public event delegat exit;
private void a_FormClosed(object sender, FormClosedEventArgs e)
{
if(exit != null)
{
exit(100);//here should run my event named exit but i get exception!
}
}
}
}
Class b
{
a instance=new a();
instance.exit+=new delegat(my_fun);
...
priavte void my_fun(int x)
{
if(x==100)
do_smth;
...
}
}

How to dispatch events in C#

I wish to create own events and dispatch them.
I never done this before in C#, only in Flex.. I guess there must be a lot of differencies.
Can anyone provide me a good example?
There is a pattern that is used in all library classes. It is recommended for your own classes too, especially for framework/library code. But nobody will stop you when you deviate or skip a few steps.
Here is a schematic based on the simplest event-delegate, System.Eventhandler.
// The delegate type. This one is already defined in the library, in the System namespace
// the `void (object, EventArgs)` signature is also the recommended pattern
public delegate void Eventhandler(object sender, Eventargs args);
// your publishing class
class Foo
{
public event EventHandler Changed; // the Event
protected virtual void OnChanged() // the Trigger method, called to raise the event
{
// make a copy to be more thread-safe
EventHandler handler = Changed;
if (handler != null)
{
// invoke the subscribed event-handler(s)
handler(this, EventArgs.Empty);
}
}
// an example of raising the event
void SomeMethod()
{
if (...) // on some condition
OnChanged(); // raise the event
}
}
And how to use it:
// your subscribing class
class Bar
{
public Bar()
{
Foo f = new Foo();
f.Changed += Foo_Changed; // Subscribe, using the short notation
}
// the handler must conform to the signature
void Foo_Changed(object sender, EventArgs args) // the Handler (reacts)
{
// the things Bar has to do when Foo changes
}
}
And when you have information to pass along:
class MyEventArgs : EventArgs // guideline: derive from EventArgs
{
public string Info { get; set; }
}
class Foo
{
public event EventHandler<MyEventArgs> Changed; // the Event
...
protected virtual void OnChanged(string info) // the Trigger
{
EventHandler handler = Changed; // make a copy to be more thread-safe
if (handler != null)
{
var args = new MyEventArgs(){Info = info}; // this part will vary
handler(this, args);
}
}
}
class Bar
{
void Foo_Changed(object sender, MyEventArgs args) // the Handler
{
string s = args.Info;
...
}
}
Update
Starting with C# 6 the calling code in the 'Trigger' method has become a lot easier, the null test can be shortened with the null-conditional operator ?. without making a copy while keeping thread-safety:
protected virtual void OnChanged(string info) // the Trigger
{
var args = new MyEventArgs{Info = info}; // this part will vary
Changed?.Invoke(this, args);
}
Events in C# use delegates.
public static event EventHandler<EventArgs> myEvent;
static void Main()
{
//add method to be called
myEvent += Handler;
//call all methods that have been added to the event
myEvent(this, EventArgs.Empty);
}
static void Handler(object sender, EventArgs args)
{
Console.WriteLine("Event Handled!");
}
Using the typical .NET event pattern, and assuming you don't need any special arguments in your event. Your typical event and dispatch pattern looks like this.
public class MyClassWithEvents
{
public event EventHandler MyEvent;
protected void OnMyEvent(object sender, EventArgs eventArgs)
{
if (MyEvent != null)
{
MyEvent(sender, eventArgs);
}
}
public void TriggerMyEvent()
{
OnMyEvent(sender, eventArgs);
}
}
Tying something into the event can be as simple as:
public class Program
{
public static void Main(string[] args)
{
MyClassWithEvents obj = new MyClassWithEvents();
obj.MyEvent += obj_myEvent;
}
private static void obj_myEvent(object sender, EventArgs e)
{
//Code called when my event is dispatched.
}
}
Take a look at the links on this MSDN page
Look into 'delegates'.
Define a delegate
Use the delegate type as field/property (adding the 'Event' keyword)
You are now exposing events that users can hook into with "+= MyEventMethod;"
Hope this helps,

C# event handling (compared to Java)

I am currently having a hardtime understanding and implementing events in C# using delagates. I am used to the Java way of doing things:
Define an interface for a listener type which would contain a number of method definitions
Define adapter class for that interface to make things easier if I'm not interested in all the events defined in a listener
Define Add, Remove and Get[] methods in the class which raises the events
Define protected fire methods to do the dirty work of looping through the list of added listeners and calling the correct method
This I understand (and like!) - I know I could do this exactly the same in c#, but it seems that a new (better?) system is in place for c#. After reading countless tutorials explaining the use of delegates and events in c# I still am no closer to really understanding what is going on :S
In short, for the following methods how would I implement the event system in c#:
void computerStarted(Computer computer);
void computerStopped(Computer computer);
void computerReset(Computer computer);
void computerError(Computer computer, Exception error);
^ The above methods are taken from a Java application I once made which I'm trying to port over to c#.
Many many thanks!
You'd create four events, and methods to raise them, along with a new EventArgs-based class to indicate the error:
public class ExceptionEventArgs : EventArgs
{
private readonly Exception error;
public ExceptionEventArgs(Exception error)
{
this.error = error;
}
public Error
{
get { return error; }
}
}
public class Computer
{
public event EventHandler Started = delegate{};
public event EventHandler Stopped = delegate{};
public event EventHandler Reset = delegate{};
public event EventHandler<ExceptionEventArgs> Error = delegate{};
protected void OnStarted()
{
Started(this, EventArgs.Empty);
}
protected void OnStopped()
{
Stopped(this, EventArgs.Empty);
}
protected void OnReset()
{
Reset(this, EventArgs.Empty);
}
protected void OnError(Exception e)
{
Error(this, new ExceptionEventArgs(e));
}
}
Classes would then subscribe to the event using either a method or a an anonymous function:
someComputer.Started += StartEventHandler; // A method
someComputer.Stopped += delegate(object o, EventArgs e)
{
Console.WriteLine("{0} has started", o);
};
someComputer.Reset += (o, e) => Console.WriteLine("{0} has been reset");
A few things to note about the above:
The OnXXX methods are protected so that derived classes can raise the events. This isn't always necessary - do it as you see fit.
The delegate{} piece on each event declaration is just a trick to avoid having to do a null check. It's subscribing a no-op event handler to each event
The event declarations are field-like events. What's actually being created is both a variable and an event. Inside the class you see the variable; outside the class you see the event.
See my events/delegates article for much more detail on events.
You'll have to define a single delegate for that
public delegate void ComputerEvent(object sender, ComputerEventArgs e);
ComputerEventArgs would be defined like this:
public class ComputerEventArgs : EventArgs
{
// TODO wrap in properties
public Computer computer;
public Exception error;
public ComputerEventArgs(Computer aComputer, Exception anError)
{
computer = aComputer;
error = anError;
}
public ComputerEventArgs(Computer aComputer) : this(aComputer, null)
{
}
}
The class that fires the events would have these:
public YourClass
{
...
public event ComputerEvent ComputerStarted;
public event ComputerEvent ComputerStopped;
public event ComputerEvent ComputerReset;
public event ComputerEvent ComputerError;
...
}
This is how you assign handlers to the events:
YourClass obj = new YourClass();
obj.ComputerStarted += new ComputerEvent(your_computer_started_handler);
Your handler is:
private void ComputerStartedEventHandler(object sender, ComputerEventArgs e)
{
// do your thing.
}
The main difference is that in C# the events are not interface-based. Instead, the event publisher declares the delegate which you can think of as a function pointer (although not exactly the same :-)). The subscriber then implements the event prototype as a regular method and adds a new instance of the delegate to the event handler chain of the publisher. Read more about delegates and events.
You can also read short comparison of C# vs. Java events here.
First of all, there is a standard method signature in .Net that is typically used for events. The languages allow any sort of method signature at all to be used for events, and there are some experts who believe the convention is flawed (I mostly agree), but it is what it is and I will follow it for this example.
Create a class that will contain the event’s parameters (derived from EventArgs).
public class ComputerEventArgs : EventArgs
{
Computer computer;
// constructor, properties, etc.
}
Create a public event on the class that is to fire the event.
class ComputerEventGenerator // I picked a terrible name BTW.
{
public event EventHandler<ComputerEventArgs> ComputerStarted;
public event EventHandler<ComputerEventArgs> ComputerStopped;
public event EventHandler<ComputerEventArgs> ComputerReset;
...
}
Call the events.
class ComputerEventGenerator
{
...
private void OnComputerStarted(Computer computer)
{
EventHandler<ComputerEventArgs> temp = ComputerStarted;
if (temp != null) temp(this, new ComputerEventArgs(computer)); // replace "this" with null if the event is static
}
}
Attach a handler for the event.
void OnLoad()
{
ComputerEventGenerator computerEventGenerator = new ComputerEventGenerator();
computerEventGenerator.ComputerStarted += new EventHandler<ComputerEventArgs>(ComputerEventGenerator_ComputerStarted);
}
Create the handler you just attached (mostly by pressing the Tab key in VS).
private void ComputerEventGenerator_ComputerStarted(object sender, ComputerEventArgs args)
{
if (args.Computer.Name == "HAL9000")
ShutItDownNow(args.Computer);
}
Don't forget to detach the handler when you're done. (Forgetting to do this is the biggest source of memory leaks in C#!)
void OnClose()
{
ComputerEventGenerator.ComputerStarted -= ComputerEventGenerator_ComputerStarted;
}
And that's it!
EDIT: I honestly can't figure out why my numbered points all appear as "1." I hate computers.
there are several ways to do what you want. The most direct way would be to define delegates for each event in the hosting class, e.g.
public delegate void ComputerStartedDelegate(Computer computer);
protected event ComputerStartedDelegate ComputerStarted;
public void OnComputerStarted(Computer computer)
{
if (ComputerStarted != null)
{
ComputerStarted.Invoke(computer);
}
}
protected void someMethod()
{
//...
computer.Started = true; //or whatever
OnComputerStarted(computer);
//...
}
any object may 'listen' for this event simply by:
Computer comp = new Computer();
comp.ComputerStarted += new ComputerStartedDelegate(
this.ComputerStartedHandler);
protected void ComputerStartedHandler(Computer computer)
{
//do something
}
The 'recommended standard way' of doing this would be to define a subclass of EventArgs to hold the Computer (and old/new state and exception) value(s), reducing 4 delegates to one. In this case that would be a cleaner solution, esp. with an Enum for the computer states in case of later expansion. But the basic technique remains the same:
the delegate defines the signature/interface for the event handler/listener
the event data member is a list of 'listeners'
listeners are removed using the -= syntax instead of +=
In c# events are delegates. They behave in a similar way to a function pointer in C/C++ but are actual classes derived from System.Delegate.
In this case, create a custom EventArgs class to pass the Computer object.
public class ComputerEventArgs : EventArgs
{
private Computer _computer;
public ComputerEventArgs(Computer computer) {
_computer = computer;
}
public Computer Computer { get { return _computer; } }
}
Then expose the events from the producer:
public class ComputerEventProducer
{
public event EventHandler<ComputerEventArgs> Started;
public event EventHandler<ComputerEventArgs> Stopped;
public event EventHandler<ComputerEventArgs> Reset;
public event EventHandler<ComputerEventArgs> Error;
/*
// Invokes the Started event */
private void OnStarted(Computer computer) {
if( Started != null ) {
Started(this, new ComputerEventArgs(computer));
}
}
// Add OnStopped, OnReset and OnError
}
The consumer of the events then binds a handler function to each event on the consumer.
public class ComputerEventConsumer
{
public void ComputerEventConsumer(ComputerEventProducer producer) {
producer.Started += new EventHandler<ComputerEventArgs>(ComputerStarted);
// Add other event handlers
}
private void ComputerStarted(object sender, ComputerEventArgs e) {
}
}
When the ComputerEventProducer calls OnStarted the Started event is invoked which in turn will call the ComputerEventConsumer.ComputerStarted method.
The delegate declares a function signature, and when it's used as an event on a class it also acts as a collection of enlisted call targets. The += and -= syntax on an event is used to adding a target to the list.
Given the following delegates used as events:
// arguments for events
public class ComputerEventArgs : EventArgs
{
public Computer Computer { get; set; }
}
public class ComputerErrorEventArgs : ComputerEventArgs
{
public Exception Error { get; set; }
}
// delegates for events
public delegate void ComputerEventHandler(object sender, ComputerEventArgs e);
public delegate void ComputerErrorEventHandler(object sender, ComputerErrorEventArgs e);
// component that raises events
public class Thing
{
public event ComputerEventHandler Started;
public event ComputerEventHandler Stopped;
public event ComputerEventHandler Reset;
public event ComputerErrorEventHandler Error;
}
You would subscribe to those events with the following:
class Program
{
static void Main(string[] args)
{
var thing = new Thing();
thing.Started += thing_Started;
}
static void thing_Started(object sender, ComputerEventArgs e)
{
throw new NotImplementedException();
}
}
Although the arguments could be anything, the object sender and EventArgs e is a convention that's used very consistently. The += thing_started will first create an instance of the delegate pointing to target method, then add it to the event.
On the component itself you would typically add methods to fire the events:
public class Thing
{
public event ComputerEventHandler Started;
public void OnStarted(Computer computer)
{
if (Started != null)
Started(this, new ComputerEventArgs {Computer = computer});
}
}
You must test for null in case no delegates have been added to the event. When you make the method call however all delegates which have been added will be called. This is why for events the return type is void - there is no single return value - so to feed back information you would have properties on the EventArgs which the event handlers would alter.
Another refinement would be to use the generic EventHandler delegate rather than declaring a concrete delegate for each type of args.
public class Thing
{
public event EventHandler<ComputerEventArgs> Started;
public event EventHandler<ComputerEventArgs> Stopped;
public event EventHandler<ComputerEventArgs> Reset;
public event EventHandler<ComputerErrorEventArgs> Error;
}
Thank you all so much for your answers! Finally I'm starting to understand what is going on. Just one thing; It seems that if each event had a different number/type of arguments I'd need to create a different :: EventArgs class to deal with it:
public void computerStarted(Computer computer);
public void computerStopped(Computer computer);
public void computerReset(Computer computer);
public void breakPointHit(Computer computer, int breakpoint);
public void computerError(Computer computer, Exception exception);
This would require three classses to deal with the events!? (Well two custom, and one using the default EventArgs.Empty class)
Cheers!
Ok, FINAL clarification!: So this is pretty much the best I can do code-wise to implement those events?
public class Computer {
public event EventHandler Started;
public event EventHandler Stopped;
public event EventHandler Reset;
public event EventHandler<BreakPointEvent> BreakPointHit;
public event EventHandler<ExceptionEvent> Error;
public Computer() {
Started = delegate { };
Stopped = delegate { };
Reset = delegate { };
BreakPointHit = delegate { };
Error = delegate { };
}
protected void OnStarted() {
Started(this, EventArgs.Empty);
}
protected void OnStopped() {
Stopped(this, EventArgs.Empty);
}
protected void OnReset() {
Reset(this, EventArgs.Empty);
}
protected void OnBreakPointHit(int breakPoint) {
BreakPointHit(this, new BreakPointEvent(breakPoint));
}
protected void OnError(System.Exception exception) {
Error(this, new ExceptionEvent(exception));
}
}
}

Categories

Resources