How does PropertyDescriptor.AddValueChanged work? - c#

I'm intersted in the details of this method.
How and by what are property's value changes being tracked?

Andrew Smith has a cool blog post about it which I think it can be helpful for you.
The solution that I have seen given for this is to get to the
PropertyDescriptor and use its AddValueChanged method to provide an
EventHandler to receive a notification when the property has changed.
Sometimes, the reply will mention/use DependencyPropertyDescriptor
directly but its the same thing since that is just a derived
PropertyDescriptor that provides additional information about the
underlying DependencyProperty it represents. You can get to this
property descriptor in a few ways but the most common are to get it
from the TypeDescriptor.GetProperties method or using the
DependencyPropertyDescriptor.FromProperty.
The issue with this approach is that it will root your object so it
will never get collected by the GC. There have been plenty of
discussions about how hooking events (particularly static events) can
root your object so I won’t go into great detail there. While it does
not seem that you are hooking a static event in this case, in essence
you are. When you add a handler to a property descriptor, that
property descriptor stores the delegate in a hashtable keyed by the
object whose property you are hooking. A delegate/handler is basically
a pointer to a method on an object (or no object if its for a static
method) so that means the property descriptor has a reference to your
object as well as the object whose value you are watching (since that
is the key into the hashtable). The property descriptors themselves
are cached statically so the hashtable is kept around and therefore
your object and the one you are watching are as well.

PropertyDescriptor is an abstract class, so there are presumably many answers to how the value changed event is fired depending on the specific implementation you have at hand. But probably a common case is when a PropertyDescriptor has been acquired through reflection, in which case I think an object of ReflectPropertyDescriptor is returned.
Looking in the reference source for that class, you can see that the event is raised ONLY when the SetValue() method is called. To my understanding this means that if you simply did this:
someObject.A = "value";
there would be no ValueChanged event raised.
However if you got the ReflectPropertyDescriptor for property A and used it to indirectly set the value, like this:
descriptor.SetValue(someObject, "value");
that would raise the event.
To think about this from another point of view, it seems the CLR has no way to actually raise an event at a more fundamental level when a property value is set. I assume something like that would have overhead that would ordinarily be undesirable because each set (really just a function call) would have to check for event subscribers even if there were none, each time a value is set on any property.

Related

Object Reset method or new reference for event subscribers?

(Using VS2010. Assume performance is not an issue).
I have a particular object that implements events for all its property changes. Sometimes it will be necessary to "reset" the object to all its default property values. The easiest way to do this is simply construct a new object:
Object1= New MyObject
However, for any event subscribers to the original object, this is equivalent to a change of all property values. For example, if a subscriber was listening only for updates to property A, now it must also be aware of the possibility of new object construction. This seems to add extra effort for subscribers. (For example, maybe I would have to create a "NewObjectAssigned" event, and subscribers to property changes would need to handle that as well.)
So instead I was thinking of outfitting the object with a Reset method, so the above code changes to:
Object1.Reset
That way the Object1 reference never changes, and the Reset would manually change all properties to default values, thereby triggering all propertychanged events. But this also doesn't feel quite right, and cumbersome compared to just declaring a new object. I guess it irks me to need a method that either manually resets all properties or raises all changed events - I'd have to remember to update this method whenever new properties are added to the class. Or perhaps this isn't as problematic as I'm making it out to be.
This is a simple enough scenario that I'm sure there is a best practices for this, one way or another. Which is preferable?
If you need your event handlers to stay attached, then you'll want to use a reset instead of creating a new instance. If your object implements INotifyPropertyChanged, then you can send a single event for the reset with PropertyName set to null.
From MSDN:
An Empty value or null for the propertyName parameter indicates that all of the properties have changed.
I think I agree with Peter Ritchie's first comment, that my original question was lacking in details necessary to determine a "preferable" method. As it stands, I'm probably going with his suggestion of a wrapper class, that will be responsible for handling new object references and exposing events to subscribers.

Dictionary of events

Is there anything in c# that you can use to create a collection of events like lists, hashsets, and a dictionary in this case? Thankyou.
Sure you can:
Dictionary<String, Delegate> m_events = new Dictionary<String, Delegate>();
In Jeff Richter's Book CLR via C# you can find a complete implementation of an EventSet class.
(Even if you don't have the book you can download the sample code from https://www.wintellect.com/wp-content/uploads/2017/09/CLR-via-C-4th-Edition-Code.zip. The class in question is in "Ch11-1-EventSet.cs".)
As far as the question goes what an event is:
Say you have this line of code in your class:
public event EventHandler<NewMailEventArgs> NewMail;
then the C# compiler will translate the line above into three constructs:
A private delegate field. (Something like: private EventHandler<NewMailEventArgs> NewMail;
A public add_Xxx method (where Xxx is the Event name) that interested subscribers can use to register a callback delegate with the event.
A public remove_Xxx method (where Xxx is the Event name) that subscribers can use to unregister from the event.
(All the gory details can be found in section 11.2 of aforementioned book.)
So in other words the 'thing' you can store in your Event collection class is just a plain old delegate nothing else.
An event is like a property or method; you cant store instances of them. You can use reflection, but this likely isn't what you want.
Did you mean you want to store a list of methods to call when your event is fired? Events already do that.
EDIT:
Ah, I think I get it now. If you just simply fire your event, only the B instances that want it will get it. If you pass into the event args the instance of A that fired the event, then the B instance will be able to tell where it came from. But a B will never get an event from an A that it didn't ask for an event.
EDIT:
Maybe not. You only want to fire an event on one of the B's? Make B implement an interface that has a callback method. Instead of firing an event, call the method on the correct instance of B.
You could use IList with out any trouble. Type T could be any type defined in .net or user defined class.

How to decide between a method or event?

I read a question ages ago "How do C# Events work behind the scenes?" and Jon answered that all events are similar to methods...
In a purely hypothetical situation, I was wondering if someone could explain or point me to a resource that says when to use an event over a method?
Basically, If I want to have a big red/green status picture which is linked to a Bool field, and I wanted to change it based on the value of the bool, should I:
a) Have a method called Changepicture which is linked to the field and changes the state of the bool and the picture.
b) Have a get/set part to the field and stick an event in the set part.
c) Have a get/set part to the field and stick a method in the set part.
d) Other?
To gain more information about events see this post.
You have options.
If your object already implements INotifyPropertyChanged and your red/green picture is a control which supports databinding, then you can simply fire the NotifyPropertyCHanged event on the bool's set method, and add a databinding on that property to your control.
If not implementing INotifyPropertyChanged, I would still recommend doing something similar. I.e. creating your own event handler, and having the reg/green picture subscribe to the event. Just straight up calling a method from the set of your property creates a tight coupling, which is generally a bad thing to do.
The answer is: It depends.
If your boolean value is in the codebehind class of your visual component (e.g. WinForm) you can call a method ChangePicture without doing strange things. But if your boolean value is architectural more far away from the visual component an event is the right way to handle the scenario because you can not easily call a method on the visual component because the class that contains the boolean value perhaps doesn´t even know your visual component exists. :)
The best way to figure out what you should do is to look at classes in the .NET framework and see how they are designed.
Methods are "doers" or "actions", while you can see events as notification mechanisms. That is if others could be interested is being notified when something happens in an object then you can surface an event and have one or more subscribers to these events.
Since events in .NET are multi-cast, meaning multiple objects can subscribe and therefore be notified of an event happening, that may be other reason to raise an event in your objects. Events also follow the observer pattern in that the subject (your class) is really unaware of the subscribers (loosely coupled). While in order to call a method, the secondary object needs to have a reference to an instance of your class.
Note that, a method in your class eventually raises and event. So let's say you have a method in your class called ChangePicture. Then in the method's implementation, you could eventually raise an event PictureChanged. if someone is interested in being notified of this event, they can subscribe to this event. This someone is typically not the one that made the method call to change the picture.
Events are delegates. Delegates are objects. Event's are actually MulticastDelegates (a base class in the .NET framework). These objects eventually call a method, which is the method that gets called as part of the event notification. So they are slightly "heavier" then just a method call, but that should almost never determine your design.

Why can I check some event handlers for null, some not?

I have a ugly piece of code that adds event handlers. The problem is, if the code is called multiple times, the event handlers are called multiple times.
To solve the problem, I remove the event handler first and then add it.
Now I've seen the following behaviour:
Some event handlers can be checked like:
if (object.event == null) {
//
// Code
//
}
others of the form
if (object.object.event == null) {
//
// Code
//
}
I get a message like 'object.object.event' may only occur left of -= or +=.
(Since I'm using a german version of visual studio, I don't know the correct translation to english).
I have no idea why the behaviour looks this inconsequent so I would be grateful for some information on this.
To be more specific: It's user control.
if (myControl.Event == null) {
//
// works
//
}
if (myControl.TreeView.NodeMouseClick == null) {
//
// doesn't work
//
}
To solve the problem, I remove the event handler first and then add it.
That doesn't solve the problem. The event keyword provides accessors for a delegate object. Much like a property provides accessors for a field. On a property, you always need one get or set. An event has the add, remove and raise accessors. But the compiler will generate a default implementation for them if you don't do so yourself. Which is fairly common.
The advantage of a property accessor is that the backing field can be private. Nobody can mess with it, except the class that contains the field. All access has to go through the get and set accessors. The event keyword works exactly the same way, nobody can mess with the delegate object, except the code in the class that contains the event.
Which shoots a gaping hole in your attempt to avoid raising the event. You cannot mess with the list of subscribers for an event that's declared in another class, the compiler is telling you this. The normal way this is done is setting a bool flag to indicate that events have to be temporarily ignored. The event handler can check that flag and avoid executing any side-effects.
SLaks is correct, and has linked to some excellent resources. Here's a relevant quote from Chris Burrows' blog article:
Let me take a quick detour here and explain to you how the binding of += works in C#. There are two possibilities:
either there is an actual + operator, such as with ints, and x += y binds to “x = x + y” except that x is only evaluated once. This is the compound assignment operator; or
the thing on the left hand side is an event, and x.E += y binds to “x.add_E(y)”. This is the event accessor operator, and in fact this is the only way to bind to an event accessor.
So what do we have in the snippet above? Well, the extra bit of detail that you need to decide is the following rule about field-like events in C#: outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.
In your case, when resolving myControl.Event, you're inside the myControl class, so you don't see an event object; instead you see an actual delegate object, which you can compare with null. When resolving myControl.TreeView.NodeMouseClick, you're outside the TreeView class, so you can't access the actual delegate object; all you get is the event object, which cannot be compared to null.
If I understand correctly, all of this wouldn't help you anyway, since presumably after you check for null, you're going to try to fire the TreeView's event for it, which you can't do.
Depending on what you're trying to do, you could probably subclass TreeView and add an internal method that would call the protected TreeView.OnNodeMouseClick method to fire the event.
You can only access the backing field for an event defined in your class.
For more information, see the spec. (Although this has changed in C# 4, the changes are irrelevant to you)
Best practice in your case would be to create a protected internal OnEventName method in each class.
You can only query your own eventhandlers for attached listeners.
Automatic events, like this one:
public event EventHandler SomethingHappened;
are implemented by the compiler using a multicast delegate.
When you write myControl.Event == null, the compiler actually needs to call Delegate.GetInvocationList on that delegate. The compiler does not let you do that unless the code is inside a method of the class exposing the event, hence the error (it only allows you to add or remove from the invocation list).
If we were talking about an event you define in your own class, then you would have the option of exposing the invocation list (e.g. through a method) and doing what you are trying to do. But for existing classes (e.g. TreeView) it is not possible.

Best practice regarding the 'object' parameter of event

This question is only related to the first parameter in any event handler, that is 'object'.
I am just curious to understand the best practice that should be adopted while raising an event.
The case is simple when the event is originated from my object itself, in that case i can simply call...
RaiseSomeEvent(this, someArgs).
What should be done in case my object is acting as a middle man, and the event originates from some other object, and the middle man is just responsible for raising it again?
In that case, i will have two choice:
1) RaiseSomeEvent(sender, someArgs) // just passing the object that was passed by the source object.
2) RaiseSomeEvent( this, someArgs)
Is there any rule regarding the 'object' param of an event? like, it should have reference to the source object (the one which triggered this event), or i can do it anyway as per my requirement?
I would use the framework here for inspiration.
Typically, the case is the simplest - the object is the object raising the event.
However, there are cases where objects "filter" events and act as a middle man in the framework. The case that comes to mind is Routed Events in WPF -
In this case, the Framework uses the approach of adding a property in the EventArgs that specifies the original object, and uses "this" for the event. For details, see RoutedEventArgs.OriginalSource.

Categories