In this code I noticed the .Notify method is an extension method. Why and what is the code behind this method?
public class Notifier : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
(...)
public void NotifyPropertyChanged(Expression<Func<object>> property)
{
this.PropertyChanged.Notify(property);
}
}
This extension method isn't provided by the .NET framework. Therefore, it is a custom extension method created somewhere in your code. To know what exactly it does, navigate to it and look at the source code (F12).
Generally speaking, I assume it will raise the PropertyChanged event with the property name extracted from the expression that is passed to it.
INotifyPropertyChanged interface is used to specify to subscribed clients that value of the property has been changed. To implement it, you have to declare a PropertyChanged event.
.Notify as you have mentioned is an extension method. The soul purpose of this .Notify must be to raise this event.
Internally it must be raising the event by doing something like this
PropertyChanged(this, new PropertyChangedEventArgs(info));
For more information look at MSDN
Related
I'm studying some examples provided by Microsoft for win8 development. I opened BasicControls sample and noticed LayoutAwarePage class and more precisely ObservableDictionary class. Reading about implementing events and raising them I can't see who's responsible to raise MapChangedEventHandler event. Based on parameters I believe that private void InvokeMapChanged(CollectionChange change, K key) method do this. But according to MSDN we need to provide a protected method that begins with On which doesn't occur in ObservableDictionary.
So, who raises MapChangedEventHandler?
An event in a class can be raised from within the class without need of an additional method to that.
So, if MapChangedEventHandler is an event, it can be called from inside the class just by this:
if (MapChangedEventHandler != null)
MapChangedEventHandler( parameters );
The only motive I can see (I'm not an expert) to the existance of those OnWhatever methods is to allow raising events from outside the class, or from some derived class, since events can only be raised from inside the declaring class.
Those OnWhatever methods must be some good practice (not a rule, nor a compiler rule).
Maybe they also take care of some additional stuff together with raising the event.
If they are not provided, probably they are not meant to be called from outside or from a derived class.
By the way, the MapChangedEventHandler is not an event. It's a delegate.
Events can be of that type, but their names are independant.
Like this:
class TestClass
{
these are the events of the class:
public event MapChangedEventHandler SomeEvent1;
public event MapChangedEventHandler SomeEvent2;
public event MapChangedEventHandler SomeEvent3;
//now this method calls the events (events can only be raised from inside the class)
public void SomeMethod()
{
//do lots of stuff
if (SomeEvent1 != null) SomeEvent1(whatever arguments it takes);
//do other stuff
if (SomeEvent2 != null) SomeEvent2(another arguments);
}
//now, if you want to let derived classes to raise events...
protected void OnSomeEvent3(Same Parameters As MapChangedEventHandler)
{
if (SomeEvent3 != null) SomeEvent3(parameters);
}
}
I know the class implementing an interface must implement all its method. But what does event inside the interface mean?
It means that the type must implement the event - so that clients can subscribe to those events.
Think of events as pairs of methods (add/remove) just as properties have get/set. Just as you can have properties in interfaces, you can have events: the implementation has to provide the appropriate add/remove methods and the metadata to tie them to the event. In C# this can be done using field-like events:
public event EventHandler EventFromInterface;
or with explicit add/remove methods:
public event EventHandler EventFromInterface
{
add { ... }
remove { ... }
}
It means anything implementing that interface must raise that event. Pretty much the same as a Method or Property within an interface.
I was writing some C# code which uses events, and Resharper asked if I want to create an event invocator. It generated the following code:
LowFuel handler = lowFuel;
if (handler != null) handler();
Maybe I am missing something or a little rusty, but what is an event invocator? I know about the handler which is where the actual logic for the event will go.
Thanks
As the name implies, it's a method used to raise the event. It's usually better than directly invoking the delegate, for several reasons, because it checks whether the handler is null before trying to invoke it (so you don't need to check that every time you want to invoke the event).
Also, note that by default Resharper creates the event invocator as public and non virtual. IMHO it shouldn't be public, it usually doesn't make sense to invoke an event from outside the class that declares it. Also, it's often useful to make this method virtual, so you can override it in derived classes, rather than subscribe to the event of the base class. I always declare event invocators as follows:
protected virtual void OnFoo(FooEventArgs args)
{
var handler = Foo;
if (handler != null)
handler(this, args);
}
An event invocator (horrible term) is simply the code that invokes the event.
It's not 100% clear from your code example, but normally you'd declare LowFuel separately from the usage (in an interface perhaps) which is why you need to check it exists before calling it.
Say I have a class like this:
public class FauxIdentityForm
{
public Guid FormID { get; set; }
public event EventHandler Closed;
public void TheObjectWasClosed(EventArgs e)
{
Closed(this, e);
}
}
It is fine for me to call the Closed Event inside the TheObjectWasClosed method. But if, in a different class (even in the same file), I have a method like this:
public void CallTheEvent()
{
FauxIdentityForm _formIdentity = new FauxIdentityForm {FormID = Guid.NewGuid()};
_formIdentity.Closed(_formIdentity, null); // <-- Does not compile!
}
The call to Closed is shot down by the compiler (it wants me to only use += and -=).
So, is actually calling the event only allowed inside the class? Is that the limitation?
If so, is there anyway around it? And if not, why did the creators of C# do this? (It makes working with events very hard sometimes. I imagine there is a good reason and it is probably saving me from myself, but I would like to know it.)
It's complicated :)
What you're using is called a field-like event. When you declare one of those in your class, you're creating a field and an event. When you "call the event" you're actually invoking the delegate referred to by the field. As it's a private field, you have access to it within the class (and any nested types), but not outside.
Events themselves in C# only support add and remove operations. From the outside, callers can only subscribe to an event and unsubscribe from it. They can't raise it, or find out anything about who's subscribed. Of course, the class can provide a method which will raise the event, but the other class can't access the backing field for the event
I've written this up in more detail in an article about events and delegates.
In fact, Closed(this, e); is nothing but calling invoke on a private delegate. This is why only the class can call it.
C# hides all the complexity from you and it creates a private delegate of type event for you (you can use ILDASM to see all this).
This is private so it is not even protected. This is why it is recommended to use a protected method to raise the event so the subclasses could have access to the event.
So, is actually calling the event only allowed inside the class? Is that the limitation?
Yes
If so, is there anyway around it?
Only with the consent (help) from the FauxIdentityForm class. It could have a public OnClosed() method.
An Event is a lot like a property, one of its main purposes is encapsulation and that is what you ran into.
I want to subclass ObservableCollection to add a property to it. Unfortunately, the PropertyChanged event is protected. Basically, I want to subclass it to have a SelectedItem that I can bind to for lists in my MVVM WPF app.
Here's the skeleton of my class:
public class SelectableList<T> : ObservableCollection<T>
{
public T SelectedItem {get;set;}
}
But I cannot do the following:
SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);
because of access restrictions. This causes me to ask a deeper question. How is the UI notified of PropertyChanged events (e.g. Count property)? Note that I cannot do it in a code-behind.
My head is spinning, can someone please enlighten me?
SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged +=
new PropertyChangedEventHandler(intList_Changed);
ObservableCollection implements INotifyPropertyChanged explicitly, which means you have to cast the instance to the interface before you can access the interface's methods, properties and events. As to why this is done, I don't know. The Binding markup extension doesn't "know" ObservableCollections or any other type. It checks types to see if they implement or extend specific interfaces/base classes (INPC, INCC, DependencyObject, etc) and so doesn't care if the interface is implemented explicitly.
ObservableCollection (int .NET 3.5) appears to implement the PropertyChanged event in an interesting way.
protected event PropertyChangedEventHandler PropertyChanged;
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
This means that the protected PropertyChanged event is likely only meant to be used for internal implementation. The other INotifyPropertyChanged.PropertyChanged event is the one that actually fulfills the implementation of the INotifyPropertyChanged interface as an explicit interface. Strangely I do not see any place within the ObservableCollection where the INotifyPropertyChanged.PropertyChanged is actually raised. This may signal that this was a bug in .NET 3.5 although I haven't tested to confirm whether for example a property changed event is raised for Count when an item is added to a collection but that appears to be how it is supposed to work.
In the .NET 4.0 implementation it appears that the INotifyPropertyChanged.PropertyChanged event instead hooks to the same private delegate used by the protected PropertyChanged event which may have been a bug fix. It is also possible this is just due to differences in how auto event implementations are handled in .NET 4.0.
Correction: I have verified that the INotifyPropertyChanged.PropertyChanged event is raised by ObservableCollection so the assumptions I made above based on results from using Reflector to look at the ObservableCollection implementation must be inaccurate. My guess is that reflector is doing something strange bug I have no proof of that yet.
So to get your example to work you would need to write for this to work would look like the example below just as Will has demonstrated in his answer.
SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged +=
new PropertyChangedEventHandler(intList_Changed);
Interesting right? Using explicit interfaces is mainly used to avoid inevitable collisions in members required for a given interface but they can be used to in a sense hide the existence of a member.
If you would like to raise property change events for your own custom properties that you introduce in your subclass look into overriding and/or calling the protected OnPropertyChanged method that ObservableCollection also implements. This technique is a well adopted standard and allows subclasses to raise events or handle events without having access to the underlying event delegate. It is generally preferred to use this technique too by the way instead of having a subclass hook event handlers to it's own base classes events. For more examples look at how events in various controls are implemented in WinForms and WPF.
I tried to add a new property in
public class ResultCollection<T> : ObservableCollection<T>
{
Boolean _val;
public Boolean Val
{
get
{
return _val;
}
set
{
_val= value;
OnPropertyChanged(new PropertyChangedEventArgs("Val"));
}
}
}
I really didn't notice that PropertyChanged is defined as protected. Finally moved Val property to ViewModel.
The UI can and does get notified. This is a restriction JUST with ObservableCollection, which defines the PropertyChanged event as protected.
FWIW, I think you're better off leaving ObservableCollection alone and just adding another property to your VM.