I've been reading this MSDN article and this question to try to understand events in .NET. Unfortunately, its not clicking for me and I'm having a lot of trouble. I'm trying to integrate this technique into my project, with little success.
Basically, I've got this class that will read numbers. Whenever it encounters a new number, I want it to fire an event called numberChanged.
So, I set up my event public event EventHandler numberChanged;. Later on, I fire my event when it encounters a number than isn't the same as the previous one.
if(currentNumber != previousNumber){
if(numberChanged != null){
numberChanged(this, new EventArgs());
}
}
But then I'm having trouble 'subscibing' to this event. If I do numberChanged += [something to do here] it errors saying that numberChanged is an event and not a type.
Is my explanation clear enough for some advice to be offered? Many thanks.
There are a number of ways to handle it, the most basic is to create a function:
public void MyNumberChangedHandler(object sender, EventArgs e)
{
//Your code goes here that gets called when the number changes
}
You then subscribe (one time only, usually in the constructor) by going:
numberChanged += MyNumberChangedHandler;
Or, you can use something called an anonymous (lambda) method, which is also assigned in your constructor (typically):
numberChanged += (sender, e) => {
//Your code here to handle the number changed event
};
To expand a little bit, care must be taken when using the lambda approach since you can create memory leaks and zombie objects. The .NET memory garbage collector is a mark-and-sweep system that removes objects when they are no longer in use. This post shows how hard it is to remove lambda event handlers: How to remove a lambda event handler .
Having an active event handler can keep your object alive even if it has been disposed! Here is an example of creating a zombie object (doesn't run in Fiddle but you can copy to your own console app) https://dotnetfiddle.net/EfNpZ5
Prints out:
I'm still alive
I'm still alive
I was disposed!
Press any key to quit
I'm still alive
I'm still alive
I'm still alive.
As everything else in the C# programming world, the events concept also follows specific rules and has it's own syntax. The wording is as follows:
an event defined as EventHandler is actually just a shortcut for a special method (delegate) signature - public delegate void EventHandler(object sender, EventArgs e)[1]. Whenever you have a signature in C# you always know what you need to write on the right sight or as a parameter, in order to connect/call some objects/methods/and so on.
after the event is defined, you need to subscribe in order to be informed whenever something happens. The syntax for subscribing an event is +=. Naturally for unsubscribing is -=. MSDN says that the syntax should be object.event += eventHandler (or object.event += new EventHandler(eventHandler);)
so after an event is defined (event Event SomeEvent;) all that left is to create a method that can be bound to this event. This method has to have the same signature as the EventHandler, so it should match the signature of [1] and can be something like private void numberChangedEventHandler(object sender, EventArgs eventArguments)
Now you know what you need to write on the right side of +=.
An example:
public class NumberSequence
{
// numbers to be compared
private readonly List<int> numbers = new List<int>();
// used to generate a random collection
private readonly Random random = new Random();
// tell me if the previous and next number are different
public event EventHandler DifferentNumbersEvent;
public NumberSequence()
{
// fill the list with random numbers
Enumerable.Range(1, 100).ToList().ForEach(number =>
{
numbers.Add(random.Next(1, 100));
});
}
public List<int> Numbers { get { return numbers; } }
public void TraverseList()
{
for (var i = 1; i < this.numbers.Count; i++)
{
if (this.numbers[i - 1] != this.numbers[i])
{
if (this.DifferentNumbersEvent != null)
{
// whoever listens - inform him
this.DifferentNumbersEvent(this, EventArgs.Empty);
}
}
}
}
}
Now before the class is used, define the event handler, that will listen and will be called, when the event is fired (wording again):
private void differentNumberEventHandler(Object sender, EventArgs eventArguments)
{
Console.WriteLine("Different numbers...");
}
And the usage:
var ns = new NumberSequence();
ns.DifferentNumbersEvent += differentNumberEventHandler;
ns.TraverseList();
Everything else is just syntactic sugar for this notation (lambda / anonymous methods / ...), for example:
object.Event += (s, e) => { // code ... }; is the same as object.Event += (Object sender, EventArgs eventArguments) => { // code ... };. Do you recognise the signature? - it is the same as the private void differentNumberEventHandler....
Often we need to pass information through the event, in this case maybe we want to see the two numbers. C# allows you to do this easily using custom event arguments. Just create a class that inherits the EventArgs class and add properties for the data that should be passed, in this case the numbers:
public class NumbersInfoEventArgs : EventArgs
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
And then specify, when declaring the event, that it will pass data of type NumbersInfoEventArgs (signatures again):
public event EventHandler<NumbersInfoEventArgs> DifferentNumbersEvent;
...
this.DifferentNumbersEvent(this, new NumbersInfoEventArgs
{
Number1 = this.numbers[i - 1],
Number2 = this.numbers[i]
});
And last but now least, the signature of the event handler should match the signature of the event:
private void differentNumberEventHandler(Object sender, NumbersInfoEventArgs eventArguments)
{
Console.WriteLine("Different numbers {0} - {1}", eventArguments.Number1, eventArguments.Number2);
}
And voila, the output is:
Different numbers 89 - 86
Different numbers 86 - 53
Different numbers 53 - 12
Different numbers 12 - 69
you can subscribe the event in this way:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var num = new Number();
num.numberChanged +=(s,e) =>{
Console.WriteLine("Value was changed to {0}",num.Value); // in the demo below you can find another implementation for this sample using custom events
};
num.Value=10;
num.Value=100;
}
}
public class Number{
public event EventHandler numberChanged;
private int _value=0;
public int Value
{
get{
return _value;
}
set{
if(value!=_value){
_value=value;
if(numberChanged!=null)
numberChanged(this,null);
}
}
}
}
explanation:
since the EventHandler delegate has 2 parameters (sender, eventArgs) as mentioned here, you need to pass these params and I passed them as s and e
another way to subscribe this event like this:
var num = new Number();
num.numberChanged += NumberChanged_Event; // below is the delegate method
public void NumberChanged_Event(object sender,EventArgs e)
{
// your code goes here
}
I updated the demo to work with you own delegate to pass the old value and new value which can help in many cases.
here a working demo
Related
I am developing a MEF application. I am using a plugin as a publisher and another as a subscriber. For the current issue I guarantee that both plugin instances are active. On the subscriber I subscribe to the event and on the publisher I iterate over the invocation list and call the BeginInvoke to raise the event asynchronously as so:
Publisher:
public class BackchannelEventArgs : EventArgs {
public string Intensity { get; }
public BackchannelEventArgs(string intensity) {
this.Intensity = intensity;
}
}
public class Publisher {
public event EventHandler<BackchannelEventArgs> BackchannelEvent = delegate { };
private void BackchannelEventAux(string bcintensity) {
Plugin.LogDebug("BACKCHANNEL EVENT, sending to " + BackchannelEvent.GetInvocationList().Length + " subscribers: " + bcintensity);
var args = new BackchannelEventArgs(bcintensity);
foreach (EventHandler<BackchannelEventArgs> receiver in BackchannelEvent.GetInvocationList()) {
receiver.BeginInvoke(this, args, null, null);
}
}
}
Subscriber (relevant snippet, the Init is being called by a pluginsManager in which I can see the logs):
class Subscriber {
public void Init(){
LogInfo("Before subscribing");
publisher.BackchannelEvent += HandleBackchannelEvent;
LogInfo("After subscribing");
}
private void HandleBackchannelEvent(object sender, BackchannelEventArgs e) {
LogDebug("Handle Backchannel!");
}
}
Now, the Log you see on the event handler is not called at all. I have 4 other events that follow the same structure and somewhat this event in particular is not being called (I can see the logs on the other events). The other plugins follow the exact same structure.
Already tried:
Call synchronously BackchannelEvent(this, args) but the results are the same;
Subscribe this same event on the other plugins as well but the issue remains on this single event (and not on the others who follow the same structure).
I hope you can give me some help on this.
Thank you
Edit: The shown code is a snippet. The Init method is being called by the pluginsManager. I have put a log before the subscribing call and I can confirm that I am indeed subscribing.
Edit2: The number of elements in the InvocationList is in fact 2 (the empty delegate and the subscriber) so it checks out.
Okay. I don't know why but I figured out the solution so that other ones who stumble with the issue can find a solution. It was related with a extension I created for the Random class (which wasn't throwing a exception although... so it might be a bug on C#, I can't really explain). The Random extension is provided by an external NuGet package I created.
Version A (without using the Random Extension):
Body of the EventHandler:
LogDebug("Inside Handler");
double intensityValue2 = GetRandomNumber(Settings.MinimumIntensity, Settings.MaximumIntensity);
double frequency2 = GetRandomNumber(Settings.MinimumFrequency, Settings.MaximumFrequency);
int repetitions2 = GetRandomInt(Settings.MinimuMRepetitions, Settings.MaximumRepetitions);
Version B (using Random extension):
Body of EventHandler:
LogDebug("Inside Handler");
double intensityValue2 = random.GetRandomNumber(Settings.MinimumIntensity, Settings.MaximumIntensity);
double frequency2 = random.GetRandomNumber(Settings.MinimumFrequency, Settings.MaximumFrequency);
int repetitions2 = random.GetRandomNumber(Settings.MinimuMRepetitions, Settings.MaximumRepetitions);
Version A is the one that it is working. The Logs are guaranteed to appear. I don't know why it isn't letting me use extensions but it is solved for now. It would make sense if the Random extension threw an exception but it is not the case...
If any other person stumbles upon the issue I hope this helps you figure out the issue faster than me.
Thank you
Edit: typo
I have class Step which has a collection of Task i.e List .
Step has properties Status , Time . Task also has the same properties. The values of Status and Time for Step need to be updated whenver anyone of the Tasks get their Time or Status changed.
For this , I am adding handlers to each task in the Step class.
private void AddHandlers()
{
foreach (Task tsk in Tasks)
{
tsk.PropertyChanged += HandleStatusChanged;
tsk.PropertyChanged += HandleTimeChanged;
}
}
private void HandleStatusChanged(object sender, EventArgs e)
{
UpdateStepStatusFromTasks();
}
private void HandleTimeChanged(object sender, EventArgs e)
{
UpdateStepTimesFromTasks();
}
private void UpdateStepTimesFromTasks()
{
// logic for calculating Time for Step
}
private void UpdateStepStatusFromTasks()
{
// logic for calculating Status for Step
}
Here is the Property changed event handler in Task
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
My issue is that even if I change only Task Time , it calls both the handlers Status and time as they are subscribed to the same property changed event on task.
How can i bifurcate the Property changed event based on Property called from and ensure that only the respective handlers get called and not both together ?
Sorry if this sounds silly , but I am somewhat a beginner to WPF.
Regards,
P
You need to check the parameter of the args that are passed in to get the name of the property.
First get rid of your double subscription.
private void AddHandlers()
{
foreach (Task tsk in Tasks)
{
tsk.PropertyChanged += HandlePropertyChanged;
}
}
Then use the correct signature for your event so you get the correct type of event args.
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
Now that we have PropertyChangedEventArgs instead of just EventArgs we can check the PropertyName property and call the needed method.
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case "Status":
UpdateStepStatusFromTasks();
break;
case "Time":
UpdateStepTimesFromTasks();
break;
}
}
As you need more properties handled you can just add them to the switch statement.
P.S. Instead of manually subscribing to each Task you can use a BindingList<Task> as the collection that holds the tasks, you can then subscribe to the ListChanged event, that event will be raised if any of the items in the list raise PropertyChanged (be sure to enable RaiseListChangedEvents and check ListChangedEventArgs.ListChangedType is equal to ListChangedType.ItemChanged).
Every event has "accessors" add or remove. Something similar like get/set for properties. This accessors can show you the nature of the event. Every event has an InvocationList, which represents a collection of object that it will notify when the event is raised. Using this accessors you can you can have more control over what get notified and what not. When you subscribe to the event, the subscribed object get inserted into the Invocation list.
Since you are subscribing the same object for both events, you will have it triggered twice.
Only thing you can do is to check the name of the property that got updated
public void ChangedHandler(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName=="Time"){//do something}
else if (e.PropertyName == "Date") {doSomething}
}
Since you are dealing with WPF, I see a strange pattern here. You are raising the events from various methods. You should be raising the event from a property for which you want the notification to happen, which is bound to a control.
public class MyVM
{
private string _status = "status1";
public string Status
{
get
{
return _status;
}
set
{
if(_status!=value)
{
_status =value
OnPropertyChanged("Status");
}
}
}
}
You can improve on this using various things like "nameof", baseClasses, or MethorVeawers like FODY
So, the obvious thing here is that you are attaching two handlers to the `` event so everything is being processed twice. It needs be only subscribed to once.
But rather than making a lot of complicated methods with code bouncing around all over the place, I prefer to using Microsoft's Reactive Extensions (Rx) - NuGet "Rx-Main" - to do anything with events. After learning a few basic operators it really makes working with events much much easier.
Rx is, in overly simplistic terms, LINQ for Events. It lets you work with queries to handle events rather than enumerables. It creates observables.
First, I would create this observable:
var tpns = // IObservable<{anonymous}>
from t in Tasks.ToObservable()
from ep in Observable.FromEventPattern<
PropertyChangedEventHandler, PropertyChangedEventArgs>(
h => t.PropertyChanged += h,
h => t.PropertyChanged -= h)
select new { Task = t, ep.EventArgs.PropertyName };
This query basically takes the list of Tasks and converts all of the PropertyChanged events of each task in a single observable that returns each Task when that task had a property change and the PropertyName of the task that changed.
Now it's easy to create a couple more observables that filter by PropertyName and return the Task:
IObservable<Task> statusChanges =
from tpn in tpns
where tpn.PropertyName == "Status"
select tpn.Task;
IObservable<Task> timeChanges =
from tpn in tpns
where tpn.PropertyName == "Time"
select tpn.Task;
Those should be really simple to understand.
Now subscribe to each (basically like attaching to events):
IDisposable statusSubscription =
statusChanges
.Subscribe(task => UpdateStepStatusFromTasks());
IDisposable timeSubscription =
timeChanges
.Subscribe(task => UpdateStepTimesFromTasks());
You'll notice each subscription is an IDisposable. Instead of detaching from events using the -= operator you simply call .Dispose() on the subscription and all of the underlying event handlers are detached for you.
Now I would recommend changing the AddHandlers method to return an IDisposable. Then the code that calls AddHandlers can dispose of the handlers - if needed - to make sure you can clean up before exiting.
So the complete code would look like this:
private IDisposable AddHandlers()
{
var tpns = // IObservable<{anonymous}>
from t in Tasks.ToObservable()
from ep in Observable.FromEventPattern<
PropertyChangedEventHandler, PropertyChangedEventArgs>(
h => t.PropertyChanged += h,
h => t.PropertyChanged -= h)
select new { Task = t, ep.EventArgs.PropertyName };
IObservable<Task> statusChanges =
from tpn in tpns
where tpn.PropertyName == "Status"
select tpn.Task;
IObservable<Task> timeChanges =
from tpn in tpns
where tpn.PropertyName == "Time"
select tpn.Task;
IDisposable statusSubscription =
statusChanges
.Subscribe(task => UpdateStepStatusFromTasks());
IDisposable timeSubscription =
timeChanges
.Subscribe(task => UpdateStepTimesFromTasks());
return new CompositeDisposable(statusSubscription, timeSubscription);
}
The only new thing there is the CompositeDisposable which joins the two IDiposable subscriptions into a single IDisposable.
The very nice thing about this approach is that most of the code now sits nicely in a single method. It makes it easy to understand and maintain when done this way - at least after a small learning curve. :-)
This may have been asked several times, but I don't know what to search for..
Anyway. I have a class called Character. Inside of it I want to have a collision component that I have called RectangleCollision. Inside of it there is a function called IsOverlapping that checks for overlap.
I want to have a function that can be modified for each game object. For example create a function called OnBeginOverlap(); that will fire everytime the collision component detects a collision.
Is there any way that I can bind this function as delegate or event? Or something?
You have to read about events and delegates. There are plenty of examples on the web. The easiest I managed to find when I was trying to understand the subject was this:
The Simplest C# Events Example Imaginable
You can also check out the below (you can compile this as console application):
class Character
{
public delegate void OverlappingHandler(Character character, EventArgs e);
public event OverlappingHandler OverlappingEvent;
public void IsOverlapping()
{
bool overlapping = true;
if (overlapping)
{
if (OverlappingEvent != null)
{
OverlappingEvent(this, null);
}
}
}
}
class Program
{
static void Main(string[] args)
{
Character c = new Character();
c.OverlappingEvent += OverlappingEventHandler;
c.OverlappingEvent += OverlappingSecondEventHandler;
c.IsOverlapping();
Console.Read();
}
static void OverlappingEventHandler(Character character, EventArgs e)
{
Console.WriteLine("We have overlapping here!!");
}
static void OverlappingSecondEventHandler(Character character, EventArgs e)
{
Console.WriteLine("Seriously, we have overlapping !!");
}
}
So step by step:
Create a delegate, which is a bridge between your event and the code you want to run when event is triggered. You give parameters to a delegate, which are (object sender, EventArgs e) - in this example sender is the Character class, arguments are used to send additional info - for example type of character.
Create event of our delegate type
In our function IsOverlapping() there would be your logic checking if there is overlapping happening. If there is, you fire up event. You should check first if there is anything connected to the event (hence the if (OverlappingEvent != null)) - if some there is something, fire up the event.
In the Main() you create an instance of the class and...
Subscribe your event handlers to it, so the code that should be executed when the event is triggered. I connected two methods, just to show that you can subscribe more than one.
Now when you run c.IsOverlapping() this is what happens:
your logic to check overlapping runs,
if there is overlapping, there will be a check if OverlappingEvent has code subscribed (it does in Main()),
if it does event will be triggered,
code subscribed to the event runs - in this case your code in Main().
You can compile this as console app and it will display 2 lines:
We have overlapping here!!
Seriously, we have overlapping !!
Hope this helps.
I have a very simple XOML file with a single Code Activity inside the ReceiveActivity Handler.
The ReceiveActivity is mapped to an Interface called IRulesEngineService wih a single method on it.
void DoWork(int i);
the input parameter on the interface method is mapped to a property on the Xoml called I
I'm now trying to attempt to step into the Workflow Life Cycle at a point:
just before the first (and in this case only) Code Activity gets executed
just after the i parameter has been assigned to I on my Workflow.
I've tried overriding all the various methods and events on the XOML but in all cases I is always zero in all the events and overrides I've tried. And then is correctly set to the passed in Parameter within the first Code Activity. e.g. Imagine I passed in 8 to the ClientSide DoWork call.
public int I {get; set;}
protected override void Initialize(System.IServiceProvider provider)
{
I = I*10; //I is still 0
base.Initialize(provider);
I = I * 10; //I is still 0
}
//Event on Xoml Designer
private void Pinnacle_Initialized(object sender, EventArgs e)
{
I = I * 10; //I is still 0
}
//Event on Xoml Designer
private void receiveActivity1_OperationValidation(object sender, OperationValidationEventArgs e)
{
I = I * 10; //I is still 0
}
protected override void OnActivityExecutionContextLoad(IServiceProvider provider)
{
I = I * 10; //I is still 0
base.OnActivityExecutionContextLoad(provider);
I = I * 10; //I is still 0
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
DataAccess.WriteToDummyData(ConnectionString, "Pinnacle From Code Activity " + I);
//I is now magically '8' what the heck set this?
}
Anyone got any ideas on where in the Workflow Lifecycle the instantiating/binding/setting of these parameters occurs.
Looking at the .NET framework source code, it's not possible to access your data inputs within the code activity before the execution. in the ReceiveActivity class in the System.Workflow.Activities namespace there's a exact point where the inputs are populated. I've taken the class source from this link
See the image below:
As you can see in the picture inputs are populated at this point:
this.OperationHelper.PopulateInputs(this, requestContext.Inputs);
The instruction above is called just before the ReceiveActivity class executes the activity. At this stage I don't think there's a public event that can be subscribed to manipulate your data before your codeActivity1_ExecuteCode gets executed.
Hope it helps.
Hypothetically speaking, if I had two methods (event handlers) driven by the same event, which method is executed first?
Example:
obj.SomeEvent += new SomeEventHandler(method1);
obj.SomeEvent += new SomeEventHandler(method2);
Which is called first?
Thanks!
It's up to the event publisher, but usually it would be whichever handler was added to the event first. That's the default implementation for an event which is basically implemented using a delegate. So for example:
SomeDelegate eventHandlers = null;
eventHandlers += FirstHandler;
eventHandlers += SecondHandler;
eventHandlers(...);
That will definitely call FirstHandler before SecondHandler. However, there's no guarantee that an event will be implemented just using delegates like that.
EDIT: While the event handling behaviour is up to the event publisher, the delegate combination part is well-specified in the C# language specification, section 7.8.4:
[...] Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand.
The BCL Delegate.Combine method makes a similar guarantee (emphasis mine):
(Return value) A new delegate with an invocation list that concatenates the invocation lists of a and b in that order. Returns a if b is null, returns b if a is a null reference, and returns a null reference if both a and b are null references.
The first subscribed one. "First in - first served".
The default implementation will cause event handlers to be called in the order they were added, however, it is possible to customize this behaviour. If the behaviour is customized, the client cannot tell this. So the real answer to your question is that the order in which event handlers is raised "depends" and could even change at runtime, however, the vast majority of events have default implementation.
For example:
public class ReverseBling
{
private readonly List<EventHandler> _blings = new List<EventHandler>();
public event EventHandler Bling
{
add
{
_blings.Add(value);
}
remove
{
_blings.Remove(value);
}
}
public void RaiseBling()
{
for (int i = _blings.Count - 1; i >= 0; i--)
{
_blings[i](this, EventArgs.Empty);
}
}
}
private static void Main()
{
ReverseBling bling = new ReverseBling();
bling.Bling += delegate { Console.WriteLine(0);};
bling.Bling += delegate { Console.WriteLine(1); };
bling.Bling += delegate { Console.WriteLine(2); };
bling.RaiseBling();
}
Output:
2
1
0
There is no way of telling which event handler will be invoked first. Many people think the first one to subscribe will be invoked first (which is normally the case) but not specified by the CLI.