I have seen on another post this and its confusing me...
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public string MyProperty
{
set
{
if (_myProperty != value)
{
_myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
}
}
MyClass myClass = new MyClass();
myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
actual = e.PropertyName;
};
I'm wondering about the last few lines are doing to be honest, why would the user be assiging a delegate to an event? Would't they assign a method to it (as an event handler) or even an anonymous method as the event handler?
I thought that events were meant to encapsulate delegates.....?
You always subscribe to an event (or unsubscribe from it) using a delegate. Even if you do:
button.Click += HandleButtonClick;
that's equivalent to
button.Click += new EventHandler(HandleButtonClick);
When you say:
Would't they assign a method to it (as an event handler) or even an anonymous method as the event handler?
That's exactly what the last few lines of code do. That's what delegate (...) { ... } is.
I thought that events were meant to encapsulate delegates.....?
Events provide an implementation of the observer pattern, using delegates as the observers.
This syntax was introduced in C# 2.0
They are using an anonymous method here, rather than having to create an actual instance method of the class. It's generally considered cleaner.
In C# 3 and above, a Lambda expression could have been used as well.
The += adds an anonymous delegate to the event. Instead of creating a named method with the signature object sender, PropertyChangedEventArgs e, you can use C#2.0 syntax to create such delegates anonymously in the body of another function. Another way of doing it would be to use a more concise lambda syntax from C#3.5+:
myClass.PropertyChanged += (sender, e) { actual = e.PropertyName; };
They are not assigning a delegate to an event, they are adding a subscriber to that event using an anonymous method.
Also, as an aside, the NotifyPropertyChanged method should be changed to:
protected void NotifyPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
Since there is a potential race condition between the null check and invocation of the delegate.
Technically, you are correct; events encapsulate delegates. However, event handlers themselves are delegates.
Description
This class implements the INotifyPropertyChanged interface
MSDN Notifies clients that a property value has changed.
The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.
This is used for example on controls like the Datagrid. It signals the control that the property has changed and the control should rerender.
About the Event
You always subscribe to an event.
MyClass myClass = new MyClass();
myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
actual = e.PropertyName;
};
is doing the same as
MyClass myClass = new MyClass();
myClass.PropertyChanged += new PropertyChangedEventHandler(myClass_PropertyChanged);
void myClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
actual = e.PropertyName;
}
or
MyClass myClass = new MyClass();
myClass.PropertyChanged += myClass_PropertyChanged;
void myClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
actual = e.PropertyName;
}
More Information
INotifyPropertyChanged Interface
Related
What I want to do is basically remove a function from an event, without knowing the function's name.
I have a FileSystemWatcher. If a file is created/renamed it checks its name. If it matches, it then moves it to a specific location. However, if the file is locked, it makes a lambda that attaches to a timer's tick event, waiting until the file is not locked. When it isn't, it moves the file and then removes itself from the event handler. I've seen lots of ways to do this, like keeping the instance, or making a named method. I can't do either of those here. What are my options?
There is no simple method to achieve this.
Preferred approach:
I don't see why you can't save the delegate. You don't have to save the instance as some field. It can be a local variable that is captured by your anonymous event handler:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
I can't think of a single scenario where you can't use this.
Alternative approach without saving the delegate:
However, if you have such a scenario, it get's quite tricky.
You need to find the delegate that has been added as a handler to the event. Because you didn't save it, it is pretty hard to obtain it. There is no this to get a delegate of the currently executing method.
You can't use GetInvocationList() on the event either, because accessing an event outside the class it is defined in is restricted to adding and removing handlers, i.e. += and -=.
Creating a new delegate isn't possible either. While you can get access to the MethodInfo object defining your anonymous method, you can't get access to the instance of the class that method is declared in. This class is generated automatically by the compiler and calling this inside the anonymous method will return the instance of the class your normal method is defined in.
The only way I found that works is to find the field - if any - that the event uses and call GetInvocationList() on it. The following code demonstrates this with a dummy class:
void Main()
{
var foo = new Foo();
foo.Bar += (s, e) => {
Console.WriteLine("Executed");
var self = new StackFrame().GetMethod();
var eventField = foo.GetType()
.GetField("Bar", BindingFlags.NonPublic |
BindingFlags.Instance);
if(eventField == null)
return;
var eventValue = eventField.GetValue(foo) as EventHandler;
if(eventValue == null)
return;
var eventHandler = eventValue.GetInvocationList()
.OfType<EventHandler>()
.FirstOrDefault(x => x.Method == self)
as EventHandler;
if(eventHandler != null)
foo.Bar -= eventHandler;
};
foo.RaiseBar();
foo.RaiseBar();
}
public class Foo
{
public event EventHandler Bar;
public void RaiseBar()
{
var handler = Bar;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
Please note that the string "Bar" that is passed to GetField needs to be the exact name of the field that is used by the event. This results in two problems:
The field can be named differently, e.g. when using an explicit event implementation. You need to manually find out the field name.
There might be no field at all. This happens if the event uses an explicit event implementation and just delegates to another event or stores the delegates in some other way.
Conclusion:
The alternative approach relies on implementation details, so don't use it if you can avoid it.
Steps to remove event handler with lambda expression:
public partial class Form1 : Form
{
private dynamic myEventHandler;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
myEventHandler = new System.EventHandler((sender2, e2) => this.button1_Click(sender, e, "Hi there"));
this.button1.Click += myEventHandler;
}
private void button1_Click(object sender, EventArgs e, string additionalInfo)
{
MessageBox.Show(additionalInfo);
button1.Click -= myEventHandler;
}
}
I may be misunderstanding something fundamental here as I'm new to these concepts so please bear with me.
I'm currently removing methods from an event like so:
scheduleView.TouchDown -= scheduleView_TouchDown;
And then on other occasions - adding the methods:
scheduleView.TouchDown += scheduleView_TouchDown;
It all works fine so far, and I can understand it's possible to add several methods, like so:
scheduleView.TouchDown += scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_AnotherTouchDownEventHandler;
But how would I then later check what methods were wired up to this event?
Interestingly, you can't (at least, from the outside). An event is only obliged to offer 2 accessors - add and remove. There are other accessor methods defined in the CLI spec, but they aren't used in C# or anywhere else AFAIK. The key point: we can't ask an event what is subscribed (and indeed, we shouldn't need to know). All you can do is: add or remove.
If you are worried about double-subscribing, then note that if you try to unsubscribe and you haven't actually subscribed, then under every sane implementation this is simply a no-op; which means you can do:
// make sure we are subscribed once but **only** once
scheduleView.TouchDown -= scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_TouchDown;
From the perspective of the code raising the event, you rarely need to know who - simply:
// note I'm assuming a "field-like event" implementation here; otherwise,
// change this to refer to the backing-field, or the delegate from the
// event-handler-list
var handler = TouchDown;
if(handler != null) handler(this, EventArgs.Empty); // or similar
There is also a way to break the delegate list into individual subscribers, but it is very rarely needed:
var handler = TouchDown;
if(handler != null) {
foreach(EventHandler subscriber in handler.GetInvocationList()) {
subscriber(this, EventArgs.Empty);
}
}
The main uses for this are:
when you want to perform exception-handling on a per-subscriber basis
when the delegate returns a value or changes state, and you need to handle that on a per-subscriber basis
Yes: If you are within the class that publishes the Event, you can just access the delegate, and you can call the GetInvocationList method to get a list of the subscribers.
No: If you are working outside the class, as the delegate is not exposed to you. You could use reflection to get at it, but that would be a hack, at best.
In the type that declares the event, you can use GetInvocationList() to find out which delegates are subscribed:
public class EventProvider
{
public event EventHandler SomeEvent;
protected virtual void OnSomeEvent(EventArgs args)
{
if (SomeEvent != null)
{
var delegates = SomeEvent.GetInvocationList();
foreach (var del in delegates)
{
Console.WriteLine("{0} has subscribed to SomeEvent", del.Method.Name);
}
SomeEvent(this, args);
}
}
public void RaiseSomeEvent()
{
OnSomeEvent(EventArgs.Empty);
}
}
public class Program
{
public static void Main()
{
EventProvider provider = new EventProvider();
provider.SomeEvent += Callback1;
provider.SomeEvent += Callback2;
provider.RaiseSomeEvent();
}
public static void Callback1(object sender, EventArgs e)
{
Console.WriteLine("Callback 1!");
}
public static void Callback2(object sender, EventArgs e)
{
Console.WriteLine("Callback 2!");
}
}
This produces the following output:
Callback1 has subscribed to SomeEvent
Callback2 has subscribed to SomeEvent
Callback 1!
Callback 2!
I would like to hear opinions on below code snippet. Is there anything that can be improved? Is the event handler/raiser naming following best practices? I know it is not that useful to handle and raise events in the same class but this is just a snippet.
public class MyControl
{
public MyControl()
{
this.LogWritten += this.HandleMyControlLogWritten;
}
// Event handler
void HandleMyControlLogWritten(object sender, EventArgs e)
{
}
// Event object
public event Action<object, EventArgs> LogWritten;
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
if (this.LogWritten != null)
{
this.LogWritten(this, e);
}
}
}
The main change I'd recommend would be to get a copy of the event handler:
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
var handler = this.LogWritten;
if (handler != null)
{
handler(this, e);
}
}
This is important if you're planning to (eventually) use this class in a multi-threaded scenario. As such, I find that it's a good "best practice" to get into the habit of using. The issue is that, when using in multiple threads, without creating the copy, it's possible that the only "handler" attached could unsubscribe between the null check and the invocation, which would cause a runtime error. By copying to a temporary variable (the var handler = this.LogWritten;) line, you're effectively creating a "snapshot" of the subscriber list, and then checking it for null and invoking if required.
The other change is in the event declaration itself. Instead of using Action<T1,T2>:
// Event object
public event Action<object, EventArgs> LogWritten;
I would recommend using EventHandler<TEventArgs> (if you want to use a custom EventArgs subclass) or EventHandler (for standard EventArgs). These are more "standard practice", and will be what other developers expect:
// Event object
public event EventHandler LogWritten;
I'm fairly convinced that this isn't possible, but I'm going to ask nonetheless.
In order to make a single-shot subscription to events, I frequently find myself using this (self-invented) pattern:
EventHandler handler=null;
handler = (sender, e) =>
{
SomeEvent -= handler;
Initialize();
};
SomeEvent += handler;
It's quite a lot of boiler-plate, and it also makes Resharper whinge about modified closures. Is there a way of turning this pattern into an extension method or similar? A better way of doing it?
Ideally, I'd like something like:
SomeEvent.OneShot(handler)
It's not very easy to refactor to an extension method, because the only way you can refer to an event in C# is by subscribing (+=) to or unsubscribing (-=) from it (unless it's declared in the current class).
You could use the same approach as in Reactive Extensions: Observable.FromEvent takes two delegates to subscribe to the event an unsubscribe from it. So you could do something like that:
public static class EventHelper
{
public static void SubscribeOneShot(
Action<EventHandler> subscribe,
Action<EventHandler> unsubscribe,
EventHandler handler)
{
EventHandler actualHandler = null;
actualHandler = (sender, e) =>
{
unsubscribe(actualHandler);
handler(sender, e);
};
subscribe(actualHandler);
}
}
...
Foo f = new Foo();
EventHelper.SubscribeOneShot(
handler => f.Bar += handler,
handler => f.Bar -= handler,
(sender, e) => { /* whatever */ });
The following code works for me. It's not perfect to have to specify the event via a string, but I have no glue how to solve that. I guess it's not possible in the current C# version.
using System;
using System.Reflection;
namespace TestProject
{
public delegate void MyEventHandler(object sender, EventArgs e);
public class MyClass
{
public event MyEventHandler MyEvent;
public void TriggerMyEvent()
{
if (MyEvent != null)
{
MyEvent(null, null);
}
else
{
Console.WriteLine("No event handler registered.");
}
}
}
public static class MyExt
{
public static void OneShot<TA>(this TA instance, string eventName, MyEventHandler handler)
{
EventInfo i = typeof (TA).GetEvent(eventName);
MyEventHandler newHandler = null;
newHandler = (sender, e) =>
{
handler(sender, e);
i.RemoveEventHandler(instance, newHandler);
};
i.AddEventHandler(instance, newHandler);
}
}
public class Program
{
static void Main(string[] args)
{
MyClass c = new MyClass();
c.OneShot("MyEvent",(sender,e) => Console.WriteLine("Handler executed."));
c.TriggerMyEvent();
c.TriggerMyEvent();
}
}
}
I would suggest using a "custom" event so that you have access to the invocation list, and then raise the event by using Interlocked.Exchange to simultaneously read and clear the invocation list. If desired, event subscription/unsubscription/raising could be done in thread-safe manner by using a simple linked-list stack; when the event is raised, the code could, after the Interlocked.Exchange, reverse the order of stack items. For the unsubscribe method, I'd probably suggest simply setting a flag within the invocation-list item. This could in theory cause a memory leak if events were repeatedly subscribed and unsubscribed without the event ever being raised, but it would make for a very easy thread-safe unsubscribe method. If one wanted to avoid a memory leak, one could keep a count of how many unsubscribed events are still in the list; if too many unsubscribed events are in the list when an attempt is made to add a new one, the add method could go through the list and remove them. Still workable in entirely lock-free thread-safe code, but more complicated.
I know I can delegate the subscription of my event to another event,
public event EventHandler MyEvent
{
add { SomeClass.AnotherEvent += value; }
remove { SomeClass.AnotherEvent -= value; }
}
In this case, if AnotherEvent is raised, then MyEvent will be raised as well.
However in my class I cannot raise MyEvent() on my own as usual, because it says:
Error 3 The event 'MyEvent' can only appear on the left hand side of += or -=
I assume this is because the delegation of the subscription above.
Is it possible that I can delegate a subscription as well as invoke it on my own? The objective is so that MyEvent can be raised by two things, AnotherEvent as well as my own code.
Yes, you can - but you'll need your own delegate variable. You could either subscribe to SomeClass.AnotherEvent once and call your own delegate when that event is raised, or just keep subscribers twice:
private EventHandler myEvent;
public event EventHandler MyEvent
{
add
{
myEvent += value;
SomeClass.AnotherEvent += value;
}
remove
{
myEvent -= value;
SomeClass.AnotherEvent -= value;
}
}
Note that if you go for the "subscribe to SomeClass.AnotherEvent once" approach, you may want to consider only subscribing when you first see a subscription to MyEvent, and unsubscribing when myEvent becomes null after unsubscription. It can all get quite tricky in terms of disposal...
You will have to wire up your other someclass's event..
// constructor or initializer..
SomeClass.AnotherEvent += (s,e)=>{
if(MyEvent != null){
MyEvent(s,e);
}
};
// let this be implicit default event
public event EventHandler MyEvent;
protected void RaiseMyEvent(){
if(MyEvent != null){
MyEvent(this,EventArgs.Empty);
}
}
You need to invoke the delegate itself, not the event property. Because MyEvent doesn't have a backing field, that means you would have to invoke the backing field of SomeClass.AnotherEvent, which (usually) only SomeClass can do. As others have stated there are ways around this. See their answers.
I don't think you can, and if you could, I don't think that it would be logical. So I would implement the event normally, and then add an event handler to your class that listens to events from the other class.
You're basically making a class that has an event that is fired when something happens internally in the class AND something happens in a dependent class. I think that the implementation should reflect this. For example:
public MyClass()
{
this.other = new SomeClass;
other.AnotherEvent += SomeClass_AnotherEvent;
}
public event EventHandler MyEvent;
private void SomeClass_AnotherEvent(object sender, EventArgs e)
{
if (MyEvent != null)
MyEvent(this, e); // I think that it would be most logical, that you do not pass the sender
}