In several of my projects, it is becoming apparent that I need something slightly more powerful than the standard .NET events.
Basically, I want the option of within a message pump, having callbacks (events) raised to specific subscribers when the component they're interested changes.
This could be a specific I/O changing state (e.g. button closing contact) for one project, or a message received from a wireless ethernet for a specific MAC address in another.
My current line of thinking is to use a dictionary, and list of delegates against each address (for this example).
I haven't debugged this yet but is the following along the right lines?
class CustomSubscription
{
public delegate void DataReceivedHandler(object sender, DataReceivedEventArgs args);
public class DataReceivedEventArgs : EventArgs
{
public byte[] data;
}
private readonly Dictionary<int, List<DataReceivedHandler>> _subscribers;
public CustomSubscription()
{
_subscribers = new Dictionary<int, List<DataReceivedHandler>>();
}
public void AddSubscriber(int address, DataReceivedHandler callback)
{
if (false == _subscribers.ContainsKey(address))
{
_subscribers.Add(address, new List<DataReceivedHandler>());
}
_subscribers[address].Add(callback);
}
public void RemoveSubscriber(int address, DataReceivedHandler callback)
{
if (false == _subscribers.ContainsKey(address))
{
return;
}
if (_subscribers[address].Contains(callback))
{
_subscribers[address].Remove(callback);
}
}
public void HandleIncommingData(int address, object sender, byte[] payload)
{
if (false == _subscribers.ContainsKey(address))
{
// Nothing subscribed - take no action
return;
}
// Raise callbacks with all subscribers
foreach (DataReceivedHandler callback in _subscribers[address])
{
callback(sender, new DataReceivedEventArgs
{
data = payload
});
}
}
}
Looks like you are trying to implement an event aggregator pattern. There are plenty implementations already on the web. You can start from here, for example:
https://stackoverflow.com/questions/2343980/event-aggregator-implementation-sample-best-practices
Related
I have "Handlers" able to trigger "Brokers" (an object that does something - not important here).
Handlers are listening to different kind of events:
TimeEvent: Every 10 seconds, 10 minutes (...)
FileSystemEvent: Once a file copied/moved/deleted
DbEvent: When a record is added to a DB table
MailEvent: When I received an email in my Office 365 mailbox
Each handler must have:
Start and stop methods (start/stop catching events)
An instance of the associated broker
A way to "trigger" the broker (Process method + specific set of arguments).
Each handler should
Trigger the associated broker when a specific event is raised
I want to trigger brokers from the base Handler class so I centralize my logic (fire events, catch exception, manage threads etc.). However, the base handler doesn't know how to call the broker (when to call this function, what parameters to send to the Process method) >> Only specialized children handlers know how to do that.
The only way I found is to implement in the base handler an Execute method accepting an Action parameter... I don't like this approach as it's not really straight forward (child needs to call base class otherwise nothing happens). I was hoping to find a better design to handle this. In addition I can tell you my developers will tell me they don't understand how to use the system.
abstract class Handler : IHandler
{
public IBroker Broker { get; protected set; }
public event ProcessedEventHandler Processed;
protected void OnProcessed(ProcessExecutionResult result) => Processed?.Invoke(this, result);
public static IHandler Create(IBroker broker)
{
if (broker is ITimerTriggeredBroker)
return new TimeHandler((ITimerTriggeredBroker)broker);
return null;
}
protected Handler(IBroker broker)
{
if (broker == null) throw new ArgumentNullException(nameof(broker));
Broker = broker;
}
public abstract void Start();
public abstract void Stop();
protected void Execute(Action action)
{
var res = new ProcessExecutionResult();
try
{
action?.Invoke();
res.IsSuccess = true;
}
catch (Exception ex)
{
res.Exception = ex;
res.IsSuccess = false;
}
finally
{
OnProcessed(res);
}
}
}
TimeHandler (handling Time related events)
class TimeHandler : Handler
{
private readonly Timer _timer;
private readonly DateTime _start;
private readonly TimeSpan _frequency;
public TimeHandler(ITimerTriggeredBroker broker)
: base(broker)
{
_start = broker.Trigger.StartTime;
_frequency = broker.Trigger.Frequency;
_timer = new Timer(_ => Execute(broker.Process));
}
(...)
}
FileHandler (handling FileSystem related events)
class FileHandler : Handler
{
private readonly FileSystemWatcher _watcher = new FileSystemWatcher();
public FileHandler(IFileTriggeredBroker broker)
: base(broker)
{
if (!Directory.Exists(broker.Trigger.DirectoryPath))
throw new DirectoryNotFoundException("Unable to locate the supplied directory");
_watcher.Filter = broker.Trigger.Filter;
_watcher.Path = broker.Trigger.DirectoryPath;
_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName |
NotifyFilters.FileName;
_watcher.Created += (s, a) =>
{
if (IsCopied(a.FullPath)) Execute(() => broker.Process(a.FullPath));
};
}
There are several aspects to what you are trying to achieve:
The architecture should be easy to understand and follow by your programmers. It should guide them while they program and protect them from making errors.
It should be robust. For example, you should guarantee that every file created in the watched folder is processed.
In my answer I will ignore the robustness aspect. Please look at this seriously. FileSystemWatcher is not guaranteed to deliver all files created. Also, it is advisable to you separate the processing of FileSystemWatcher events in a separate thread or use .NET tasks for this.
Furthermore, I think you should consider using a queue, like Microsoft MQ, Azure Queue, RabbitMQ. You can do this directly or use a system like MassTransit.
Below I propose an architecture that will make it easier for your programmers to build upon.
General description
Divide the application in folders or different assemblies to make a clear separation between framework and specific handlers/brokers.
For each type of processing we create a specific message class and let the handler and broker implement a generic interface specific for the message type.
We will make use of the C# advanced type system to make sure that it is difficult to make mistakes and that the compiler will help the programmers to use the right things. For this we use generic interfaces and classes based on the message type class.
Main program
Here we will setup a manager that will register all handlers and brokers with their respective messages. This is a stand alone example, I suggest you use a system for dependency injection like for example AutoFac to further optimize this.
static void Main(string[] args)
{
var manager = new Manager();
manager.Register<FileHandlerMessage>(new FileHandler(), new FileBroker());
manager.Register<TimeHandlerMessage>(new TimeHandler(), new TimeBroker());
manager.Start();
Console.ReadLine();
manager.Stop();
}
Manager
The role of the Manager class is to organize for proper usage of handlers and brokers.
class Manager
{
private List<IGenericHandler> handlers = new List<IGenericHandler>();
public void Register<M>(IHandler<M> handler, IBroker<M> broker) where M : Message
{
handlers.Add(handler);
}
public void Start()
{
foreach ( var handler in handlers )
{
handler.Start();
}
}
public void Stop()
{
foreach (var handler in handlers)
{
handler.Stop();
}
}
}
Messages
For each type of broker, we will define a specific message class, derived from a common base class:
abstract class Message
{
}
class FileHandlerMessage : Message
{
public string FileName { get; set; }
}
Handlers
interface IGenericHandler
{
void Start();
void Stop();
}
interface IHandler<M> : IGenericHandler where M : Message
{
void SetBroker(IBroker<M> broker);
}
class FileHandler : IHandler<FileHandlerMessage>
{
private IBroker<FileHandlerMessage> broker;
public FileHandler()
{
}
public void SetBroker(IBroker<FileHandlerMessage> fileBroker)
{
this.broker = fileBroker;
}
public void Start()
{
// do something
var message = new FileHandlerMessage();
broker.Process(message);
}
public void Stop()
{
// do something
}
}
class TimeHandler : IHandler<TimeHandlerMessage>
{
private IBroker<TimeHandlerMessage> broker;
public void SetBroker(IBroker<TimeHandlerMessage> broker)
{
this.broker = broker;
}
public void Start()
{
// do something
var message = new TimeHandlerMessage();
broker.Process(message);
}
public void Stop()
{
// do something
throw new NotImplementedException();
}
}
Brokers
class FileBroker : IBroker<FileHandlerMessage>
{
public void Process(FileHandlerMessage message)
{
throw new NotImplementedException();
}
}
class TimeBroker : IBroker<TimeHandlerMessage>
{
public void Process(TimeHandlerMessage message)
{
throw new NotImplementedException();
}
}
Im new to programming and just wanted to know if a solution for a problem I got is appropriate.
I wanted to write a status (string) into a textbox from a class which is creating a Socket and the class listens for data to receives (in an other thread).
This is what i did:
Create the Class whithin the Form.cs with a button click:
private void button_Create_Click(object sender, EventArgs e)
{
int port;
Int32.TryParse(textBox_Port.Text, out port);
ServerSocketClass serverSocket = new ServerSocketClass(port, this);
}
The ServerSocketClass looks like:
class ServerSocketClass
{
Socket ServerSocket;
Socket Accepted;
IPEndPoint LocalEndpoint;
int Port = 1337; // just for fun
Messenger MainForm;
public ServerSocketClass(int port, Messenger form)
{
MainForm = form;
if (port != 0)
Port = port;
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
LocalEndpoint = new IPEndPoint(IPAddress.Any, Port);
MainForm.writeToMessages("Binding Endpoint to Socket...");
ServerSocket.Bind(LocalEndpoint);
MainForm.writeToMessages("Starting ServerListener Thread...");
Thread ServerListenThread = new Thread(startListening);
ServerListenThread.Name = "ServerListenerThread";
ServerListenThread.Start();
}
private void startListening()
{
ServerSocket.Listen(5);
MainForm.writeToMessages("Whaiting for incoming connections...");
Accepted = ServerSocket.Accept();
whaitForData();
}
and to update the GUI in the forms class i created a delegate and a "update" method with an invoke:
public delegate void writeMessege(string message);
public writeMessege MessegeDelegate;
public void writeToMesseges(string messege)
{
if (InvokeRequired)
{
this.Invoke(MessegeDelegate, new object[] { messege });
return;
}
textBox_Messeges.AppendText("SYSTEM: " + messege + "\n");
}
It works, but I wanted to know if this is a "valid" way to do it or if I should go to the developer hell ;-)
thanks in advance
Locke
It's a perfectly valid way to do that, although whether it is "right" depends very much on the context - how often you call it, what you want to do inside it, and the code that you need to call it. There are many different ways of doing it without invoke, but there is nothing wrong with using InvokeRequired/Invoke - that's what it's there for. You could just use an update method that invokes itself, which is almost the same as your code, but slightly less verbose:
public void WriteMessages(string message)
{
if (InvokeRequired)
{ this.Invoke(new Action<string>(WriteMessages), new object[] { message }); }
else
{ textBox_Messages.AppendText("SYSTEM: " + message + "\n"); }
}
There are a lot of posts already on Invoke/InvokeRequired. As a starting point, check:
Isn't blindly using InvokeRequired just bad practice?
I had a similar situation, where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate and an event in the class with a handler in the form was the answer. So I wanted to share it as it seems simpler (even if not necessarily a better solution).
The solution that worked for me:
I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.
Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.
I used this description to devise my own code below in the class that does the update:
public static class SubAsstToolTip
{
private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
public delegate void ToolTipShowEventHandler();
public static event ToolTipShowEventHandler ToolTipShow;
public static void Show()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = true;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
public static void Hide()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = false;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
}
Then the code in my form that was updated:
public partial class SubAsstToolTipWindow : Form
{
public SubAsstToolTipWindow()
{
InitializeComponent();
// Right after initializing create the event handler that
// traps the event in the class
SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
}
private void SubAsstToolTip_ToolTipShow()
{
if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
{
// Call other private method on the form or do whatever
ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);
}
else
{
HideToolTip();
}
}
long time ago, but I wanted you all know how I finally solved this to my full satisfaction (solved it with Events - of course ;-)):
I defined an EventArgs to pass all the Information I wanted to pass:
public class IncomingMessageEventArgs : EventArgs
{
private Message _message;
public Message Message
{
get
{
return _message;
}
}
public IncomingMessageEventArgs(Message message)
{
_message = message;
}
}
On the Class that publishes the information (to the WPF - Form) define the Event and its Handler:
public delegate void IncomingMessageEventHandler(object sender, IncomingMessageEventArgs e);
public event IncomingMessageEventHandler IncomingMessageEvent;
protected void OnIncomingMessageEvent(IncomingMessageEventArgs e)
{
if (IncomingMessageEvent != null)
IncomingMessageEvent(this, e);
}
and of course Raise the event, if the WPF Form needs to be updated (also on the "information sending class"):
OnIncomingMessageEvent(new IncomingMessageEventArgs(message));
on the WPF Class you need to listen to the events but first define a EventHandler because your information comes from a differen Thread!! :
private delegate void writeMessageToChatEventHandler(object sender, IncomingMessageEventArgs e);
now we write our method witch will handle the raised event:
// Write to Chat
private void writeMessageToChat(object sender, IncomingMessageEventArgs e)
{
try
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(new writeMessageToChatEventHandler(writeMessageToChat), new object[] { sender, e } );
return;
}
textBox_Chat.AppendText(e.Message.getFormatedMessageText() + "\n");
}
catch (Exception ex)
{
writeLogToChat(this, new IncomingLogEventArgs("ERROR: " + ex.Message));
}
}
and finally, we need to subscribe to the event of course (the first method, you can ignore, its just to meet the MS Nameing conventions:
private void ClientSocket_IncomingMessageEvent(object sender, IncomingMessageEventArgs e)
{
writeMessageToChat(sender, e);
}
ClientSocket.IncomingMessageEvent += ClientSocket_IncomingMessageEvent;
Hopefully I made this understandable :P
Thanks to all the people how helped me!
bye
I want to send an alert message to any subscribers when a trap occurred.
The code I created works fine using a delegate method myDelegate del.
My questions are:
I want to know whether it's better to use EventHandler instead of a delegate?
I'm not sure what the differences are between a delegate and an EventHandler in my case.
notify(trapinfo t), that's what I've done here to get trap information. But it seems not to be a good idea. I read some online tutorial lesson introducing passing delegate object; I'm wondering if it's appropriate in my case? And how should I do it? Any suggestions?
Thanks a lot :)
My code:
public class trapinfo
{
public string info;
public string ip;
public string cause;
}
public class trap
{
public delegate void myDelegate(trapinfo t);
public myDelegate del;
trapinfo info = new trapinfo();
public void run()
{
//While(true)
// If a trap occurred, notify the subscriber
for (; ; )
{
Thread.Sleep(500);
foreach (myDelegate d in del.GetInvocationList())
{
info.cause = "Shut Down";
info.ip = "192.168.0.1";
info.info = "Test";
d.Invoke(info);
}
}
}
}
public class machine
{
private int _occuredtime=0;
public trapinfo info = new trapinfo();
public void notify(trapinfo t)
{
++_occuredtime;
info.cause = t.cause;
info.info = t.info;
info.ip = t.ip;
getInfo();
}
public void subscribe(trap t)
{
t.del += new trap.myDelegate(notify);
}
public void getInfo()
{
Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
info.cause, info.info, info.ip,_occuredtime);
}
}
class Program
{
static void Main(string[] args)
{
trap t = new trap();
machine machineA = new machine();
machineA.subscribe(t);
t.run();
}
}
Update 2013-08-12
How about the observer/observable design pattern, that looks great in my case (EventHandler).
In my case, a machine subscribes to a trap messenger. (Add a machine to an invocation list)
Once a trap occurred, I send a message to all machines which are subscribed. (Call HandleEvent to handle it)
Advantages:
don't care about GetInvocationList() anymore, just use (+=) and (-=) to decide whom to send the trap.
It's easier to understand the logic of my program.
I know there are several ways to do it, but I wish I could analyze its pros and cons.
And thanks for your comments and suggestions, that would be very helpful!
I read the MSDN EventArgs article which Matthew Watson suggested.
Here's my Event Version:
public class TrapInfoEventArgs : EventArgs
{
public int info { get; set; }
public string ip { get; set; }
public string cause { get; set; }
}
public class trap
{
public event EventHandler<TrapInfoEventArgs> TrapOccurred;
protected virtual void OnTrapOccurred(TrapInfoEventArgs e)
{
EventHandler<TrapInfoEventArgs> handler = TrapOccurred;
if (handler != null)
{
handler(this, e);
}
}
public void run()
{
//While(true)
// If a trap occurred, notify the subscriber
for (; ; )
{
Thread.Sleep(500);
TrapInfoEventArgs args = new TrapInfoEventArgs();
args.cause = "Shut Down";
OnTrapOccurred(args);
}
}
}
public class machine
{
public void c_TrapOccurred(object sender, TrapInfoEventArgs e)
{
Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
e.cause, e.info, e.ip, DateTime.Now.ToString());
}
}
class Program
{
static void Main(string[] args)
{
trap t = new trap();
machine machineA = new machine();
t.TrapOccurred += machineA.c_TrapOccurred; //notify machine A
t.run();
}
}
The difference between event and delegate is that:
event declaration adds a layer of protection on the delegate instance.
This protection prevents clients of the delegate from resetting the
delegate and its invocation list, and only allows adding or removing
targets from the invocation list
See What are the differences between delegates and events?
2) As I see it, your subscriber should not change delegates freely. One subscriber can assign = to it instead of adding +=. This will assign a new delegate, therefore, the previous delegate with its invocation list will be lost and previous subscribers will not be called anymore. So you should use Event for sure. Or you can change your code to make your delegate private and write additional functions for manipulating it to define your own event behavior.
//preventing direct assignment
private myDelegate del ;
public void AddCallback(myDelegate m){
del += m;
}
public void RemoveCallback(myDelegate m){
del -= m;
}
//or
public static trap operator +(trap x,myDelegate m){
x.AddCallback(m);
return x;
}
public static trap operator -(trap x, myDelegate m)
{
x.RemoveCallback(m);
return x;
}
//usage
//t.AddCallback(new trap.myDelegate(notify));
t+=new trap.myDelegate(notify);
It is much better to use an event for your example.
An event is understood by the Visual Studio Form and WPF designers, so you can use the IDE to subscribe to events.
When raising events, there is no need for you to write your own foreach handling to iterate through them.
events are the way that most programmers will expect this functionality to be accessed.
If you use a delegate, the consuming code can mess around with it in ways that you will want to prevent (such as resetting its invocation list). events do not allow that to happen.
As for your second question: Using an event you would create a class derived from EventArgs to hold the data, and pass that to the event when you raise it. The consumer will then have access to it.
See here for details: http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
I need to be able to trigger a event whenever an object is added to a Queue<Delegate>.
I created a new class that extends Queue:
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class QueueWithChange<Delegate> : Queue<Delegate>
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e) {
if (Changed != null)
{
Changed(this, e);
}
}
}
And then attached the event from another class, like such:
QueueWithChange<TimerDelegate> eventQueue = new QueueWithChange<TimerDelegate>();
//
eventQueue.Changed += new ChangedEventHandler(delegate(object s, EventArgs ex) {
//This event is not being triggered, so this code is unreachable atm...and that is my problem
if (eventQueue.Count > 0)
{
eventQueue.Dequeue().Invoke(new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(5) });
actionTimer.Stop();
}
});
But whenever I enqueue an object (eventQueue.Enqueue(something)), the attached event is not being fired.
What am I missing here?
If you mean the non-generic Queue class, then you can just override Enqueue:
public override void Enqueue(object obj)
{
base.Enqueue(obj);
OnChanged(EventArgs.Empty);
}
However, if you mean the generic Queue<T> class, then note that there is no suitable virtual method to override. You might do better to encapsulate the queue with your own class:
(** important edit: removed base-class!!! **)
class Foo<T>
{
private readonly Queue<T> queue = new Queue<T>();
public event EventHandler Changed;
protected virtual void OnChanged()
{
if (Changed != null) Changed(this, EventArgs.Empty);
}
public virtual void Enqueue(T item)
{
queue.Enqueue(item);
OnChanged();
}
public int Count { get { return queue.Count; } }
public virtual T Dequeue()
{
T item = queue.Dequeue();
OnChanged();
return item;
}
}
However, looking at your code, it seems possible that you are using multiple threads here. If that is the case, consider a threaded queue instead.
I just did write up on what I call a TriggeredQueue. It's inspired the answer by Marc Gravell.
You can find my post here: http://joesauve.com/triggeredqueuet
And the Gist here: http://gist.github.com/jsauve/b2e8496172fdabd370c4
It has four events:
WillEnqueue
WillDequeue
DidEnqueue
DidDequeue
You can hook into any of these like so:
YourQueue.WillEnqueue += (sender, e) => {
// kick off some process
};
YourQueue.DidEnqueue += (sender, e) => {
// kick off some process
// e.Item provides access to the enqueued item, if you like
};
YourQueue.WillDequeue += (sender, e) => {
// kick off some process
};
YourQueue.DidDequeue += (sender, e) => {
// kick off some process
// e.Item provides access to the dequeued item, if you like
};
One neat trick is that you can use the DidDequeue method to kick off some process to ensure that the queue is full by making a web request or loading some data from a filesystem, etc. I use this class in Xamarin mobile apps to ensure that data and images are pre-cached in order to provide a smooth user experience, instead of loading images AFTER they scroll onto the screen (like you might see in Facebook and countless other apps).
try
public new void Enqueue(Delegate d)
{
base.Enqueue(d);
OnChanged(EventArgs.Empty);
}
You have to override Enqueue, to call OnChanged.
I have a repository that uses components that report events.
I want to show the reported events in the front end.
This is the repository:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
// what do I do here?
}
void panelCom_Trace(string message)
{
if (TraceEventHandler!= null) TraceEventHandler.Invoke(this, new EventArgs());
}
}
My UI uses a Service to interface with the repository. The service is defined as:
public interface IXmlConfigurationService
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlConfigurationService : IXmlConfigurationService
{
public event EventHandler TraceEventHandler;
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_TraceEventHandler;
}
void ConfigurationRepository_TraceEventHandler(object sender, EventArgs e)
{
// this never gets hit.
if (TraceEventHandler != null) TraceEventHandler.Invoke(sender, e);
}
}
If I can get this working, I presume I can follow the same steps to get the UI displaying event reports.
How can I get the Service to report the events that are occurring in the repository?
If I understand correctly, you would need to fulfil your event. This is akin to the Observable fulfilling all listening observers in the Observer Pattern. But for events written like this:
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
if (TraceEventHandler != null)
{
TraceEventHandler(this, e);
}
}
However, perhaps you should name the event something other than TraceEventHandler because you are now exposing an event (which usually is expressed in the past tense).
It is also worth noting that you can potentially change the event args as you bubble up (if you want to). EventHandler(TEventArgs) can help with this.
You're forgetting to use delegates...
Try something like this:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public delegate void EventHandler(string parameter1, string parameter2);
public event EventHandler TraceEventHandler;
public XmlPanelRepository()
{
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
}
void panelCom_Trace(string message)
{
if (EventHandler != null)
EventHandler("Event was hit, here's the message:", message);
}
}
public interface IXmlConfigurationService
{
//irrelevant stuff removed
}
public class XmlConfigurationService : IXmlConfigurationService
{
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_EventHandler;
}
void ConfigurationRepository_EventHandler(string parameter1, string parameter2);)
{
// Do something with your parameters.
Response.Write(parameter1 + parameter2);
}
}