Is it possible in C# to connect one event to another so emitting first event will emit second one? The only way i can see is to create a stub function that will emit second event and connect the first event to this function. Compiler do not want to connect event to event or event to anonymouse function / lambda that calls another event:
class Ui { public event EventHandler OnClick; }
class Logic { public event EventHandler OnExit; }
var ui = new Ui();
var logic = new Logic();
ui.OnClick += logic.OnExit; // Not working.
ui.OnClick += ( a, b ) => logic.OnExit; // Not working either :(.
Maybe it's some decorator available or some black magic that allows to chain events without stub functions?
You cannot do this, because you generally cannot do anything to an event from outside the object which owns it except for adding and removing handlers. In particular, you cannot list the existing registered handlers, and you cannot raise it. In your case, "copying" the event is essentially the same thing in disguise, and would allow you to circumvent this restriction; therefore, it's not allowed.
See this recent answer of mine for a more in-depth explanation of why things are the way they are - I just don't feel like retyping it all here.
For your particular case, if you own both classes, the workaround is to make them cooperate specifically - make Ui be aware of the associated Logic instance, and add event handlers to Logic.OnClick in Ui.OnClick.add implementation. Of course, this introduces coupling; you can reduce it to some extent by using more generic interfaces, but you can't get rid of it entirely.
As a side note, OnClick is not a good name for a .NET event. Common naming guide says that it should be simply Click (and OnClick should be the name of a protected virtual method that raises it).
You could do this by hiding the underlying event for Logic and then controlling calls to Add/Remove which require a UI parameter.
public class UI {
public EventHandler OnClick;
}
public class Logic {
private event EventHandler _onExit;
public void AddOnExit(UI ui, EventHandler e) {
ui.OnClick += e;
_onExit += e;
}
public void RemoveOnExit(UI ui, EventHandler e) {
ui.OnClick -= e;
_onExit -= e;
}
}
Related
I have a problem with the following code
public event PortListener<DataObject, DataProcessor>.NewDataHandler OnNewDataReceived
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
this.OnNewDataReceived += (PortListener<DataObject, DataProcessor>.NewDataHandler)Delegate.Combine(OnNewDataReceived, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
this.OnNewDataReceived -= (PortListener<DataObject, DataProcessor>.NewDataHandler)Delegate.Remove(OnNewDataReceived, value);
}
}
Event OnNewDataReceived error! How to fix it
If you want to manage event add/remove yourself, it's up to you to store the delegate1, separately from the event. Your code inside add and remove is trying to treat OnNewDataReceived as a delegate, which it isn't2.
So, add a backing field with the correct delegate type and manipulate that inside your add and remove accessors.
So you'd have something like:
private PortListener<DataObject, DataProcessor>.NewDataHandler newDataHandlers;
public event PortListener<DataObject, DataProcessor>.NewDataHandler OnNewDataReceived
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
newDataHandlers += value;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
newDataHandlers -= value;
}
}
(Mucking about with Delegate.Combine was also pointless since += does that job)
As it currently stands though, this whole thing looks like wasted effort. I would guess that you're doing this to make adding and removing event handlers "thread safe" by applying the Synchronized option. But:
When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. The addition and removal operations are thread safe
(My emphasis)
So, really it should just be:
public event PortListener<DataObject, DataProcessor>.NewDataHandler OnNewDataReceived;
1Or a list of delegates, or some other data structure. After all, that's the reason why you're writing the add/remove handlers in the first place, isn't it, to manage how the event's delegate list is stored?
2There is some magic when you use a field-like event which makes the event resemble a delegate under some circumstances. But by providing your own accessors you've opted out of this being a field-like event.
My first post, apologies if this has been answered already - I have searched and searched but have not found any specifics on using Custom EventArgs with existing SystemEvents.
I am trying to take advantage of the SystemEvents.PowerModeChanged type events but would like to use my own Custom EventArgs instead of the standard PowerModeChangedEventArgs. My approach was to create a class called CustomPowerModeChangedEventArgs which inherits from PowerModeChangedEventArgs and use these instead but I don't know how to tell the PowerModeChangedEventHandler to use these new CustomEvent args. My code is as follows:
//Define the custom args which inherit from the PowerModeChangedEventArgs
public class CustomPowerModeChangedEventArgs : PowerModeChangedEventArgs
{
public string batterylevel { get; set; }
}
//event raising method with CustomArgs instead of the PowerModeChangedEventArgs
protected virtual void PowerModeChanged(object source, CustomPowerModeChangedEventArgs e)
{
}
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(PowerModeChanged);
The problem is with the PowerModeEventChangedHandler not accepting the method PowerModeChanged with the CustomArgs. Had it been a generic eventhandler I could define the args like...
public event EventHandler<CustomPowerModeChangedEventArgs> PowerModeCHanged;
...but I can't fathom how to achieve similar with a non generic event handler. I have a suspicion that it might be possible to send the new custom args to the handler using lambda expressions but I'm really not sure about this - maybe I need to define a whole new EventChangedHandler? Any advice would be greatly appreciated.
No, you don't get to decide what parameters the event handler has. Bear in mind that there's already code in the system which is going to call your event handler... how would you expect it to construct an instance of your CustomPowerModeChangedEventArgs?
If the event had been declared using EventHandler<T>, that still wouldn't have helped you - the code calling the event handler has already been written, and it's going to pass in a PowerModeChangedEventArgs that it constructs, not an instance of your type.
Now you could declare your own event using your custom event-args, and then hook into the SystemEvents so that you raise your own event (with an instance of your own event-args, however you decide to construct that) when the system event is raised... but you shouldn't expect to be able to add an event handler which requires information the event raiser (in this case the system) isn't aware of.
I have a C# class which introduce a new custom event type, and allows users add or remove listeners to it. Also I implement a method which revoves all event listeners during dispatch;
public event EventHandler DataCommited;
private void DetatchListeners()
{
if (DataCommited != null)
{
foreach (EventHandler eh in DataCommited.GetInvocationList())
{
DataCommited -= eh;
}
}
}
It is possible to implement a method which will be taking DataCommited event as an argument. So, I can unsign a set of events using one method. I tried a lot ways implementing it, but unfortunately failed to do it. I wonder if it is actually possible and how. Thank you!!!
It is possible to implement a method which will be taking DataCommited event as an argument.
Well, not really. You can take an EventInfo, but that's all. It's important to understand that this statement:
public event EventHandler DataCommited;
actually creates two things:
An event, which code in other classes can subscribe to and unsubscribe from
A field of type EventHandler, which you can use to call the handlers, or get each one individually.
A simpler implementation of your current code would simply be this:
public event EventHandler DataCommited;
private void DetatchListeners()
{
DataCommitted = null;
}
Unsubscribing from a field-like event just changes the value of the field, after all.
However, if you have an EventInfo, you don't know how that event is implement. It may be backed directly by a field - it might not be... there's no general way of asking an event for its current handlers, or setting a new list of handlers. All you can do directly with an event is subscribe and unsubscribe.
If you only use field-like events, you could use reflection to find the name of the field and set the value to null. You can't do it in general though.
See my article on delegates and events for more information.
I would pass a control of my form to another class where I will be creating events for the control, its parent control etc. I also need to detach those events at some point. But I need to ensure I wont be duplicating the events, if the event is already attached.
So I always attach events like this, for eg:
internal static void X(Control c, MouseEventHandler mouseDownEvent)
{
c.TopLevelControl.MouseDown -= mouseDownEvent;
c.TopLevelControl.MouseDown += mouseDownEvent;
}
Now I would need similar event attaching for other handlers too. For eg,
internal static void X(Control c, EventHandler event)
{
c.Enter -= event;
c.Enter += event;
}
Now I dont want to spray around this -= and += all around, instead would like to have one simple utility function so that I can call it everywhere.
Something like:
internal static void AttachEvent(this Control c,
Func<Control, MouseEventHandler> e,
MouseEventHandler m)
{
e(c) -= m;
e(c) += m;
}
So that I can call:
AttachEvent(c, control => control.MouseDown, mouseDownEvent);
But this wouldn't compile, I get two errors:
The event 'System.Windows.Forms.Control.MouseDown' can only appear on the left hand side of += or -=
and
The left-hand side of an assignment must be a variable, property or indexer
I would like to have the AttachEvent take any event as input argument, but if that's too complicated, I can live with the MouseEvents alone.
I think this is not possible. Event in C# - like a property - consists of two methods: add and remove. So if you expand event in two methods in your mind
e.add_MouseOver(Delegate)
e.remove_MouseOver(Delegate)
you will see it is not possible to pass reference to event and do something with it in other method.
Also += is part of C# syntax and only works with referencing event at left side of expression.
I thought I understand the events in C#. That sometimes they are used if you do not want to call the method directly rather than left place for custom implementation. But when?
Programmer A writes class A, programmer B writes class B. Class A should raise an event that Class B register and reacts but Class A does not know anything about function that class B uses for serving.
Could you please provide me with simple example?
public class A
{
private readonly B _B = new B();
public class A()
{
_B.MyEvent += MyEventHandler;
}
private void MyEventHandler(object sender, EventArgs e)
{
// Handle
}
}
public class B
{
public event EventHandler MyEvent;
// Call this when you raise the event so you don't
// need check if MyEvent is null.
private void OnMyEvent()
{
if (MyEvent != null) // If this is null we have no subscribers.
{
MyEvent(this, EventArgs.Empty);
}
}
}
This is pretty basic and gets the point across.
http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx
When you say "they are used if you do not want to call the method directly rather than left place for custom implementation", you make me think that you may not completely understand the difference between a simple delegate and an event. Way oversimplifying here but here's a brief explanation...
Delegates are a way of letting someone who is writing code using your code to provide their own method. As such, they don't go through the message pump and occur synchronously etc.
Events use a delegate to provide a way for you to put your own code in to respond to the event. Events go through the message pump and are appropriate when there is something you need to respond to that may be happening elsewhere. However, they will occur outside of the execution path of the currently executing code.
Happily, most people seem to get when to use one or the other by instinct. Again, gross simplification here, but hopefully enough for further reading.