Reputation: 146
I'm learning WPF and still trying to fully understand the INotifyPropertyChanged interface. I found the following example:
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)
}
}
The example follows the same format that I see often in other code. In Visual Studio 2013, I have the option of allowing the IDE to implement the interface for me explicitly. Doing so creates the following:
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
How are these two different? If I decided to use the code generated by Visual Studio, how would that look compared to the first example?
Upvotes: 2
Views: 1318
Reputation: 13888
I would suggest reading up on Event and EventHandlers in .NET.
Lets call this A
public event PropertyChangedEventHandler PropertyChanged;
and this B
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
Are similar, but there are differences.
PropertyChanged
is explicitly (you have specified the access modifier for it) public where as B PropertyChanged
is implicitly public as you are providing an implementation for a public Interface.PropertyChanged
implements the default add/remove
, which are just wrappers to PropertyChanged += handler
and ProeprtyChanged -= handler
where as B PropertyChanged
implements add/remove
as throw new exception
. Therefore if anything was to try and subscribe to the B 'PropertyChanged' event, it will throw the NotImplementedException
.PropertyChanged
event will be accesible to anyone using your class, or your class as INotifyPropertyChanged
, where as B PropertyChanged
event will ONLY be accessible once someone casts your class to INotifyPropertyChanged
.Now your other piece of code:
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)
}
}
Is used to invoke the PropertyChanged
event(if not null), and notify any subscribers that the giver propertyName
has changed. You need whenever you want to invoke events on your class from external code, as events can ONLY be invoked from within your class.
Upvotes: 2
Reputation: 6684
There's really two questions here. First, what's with the add and remove in an event and second, what is an explicit interface implementation? These are orthogonal things.
In C#, events are actually a lot like properties. An event has an add
method and a remove
method. If you don't specify them explicitly, the compiler will create them for you as well as a delegate field to back the event (which you can access from within your own class by referring to the event).
You can create the add
and remove
methods yourself if you wish (and if you want to implement the interface explicitly, you must). In that case you usually also create a delegate field to back your event:
public event EventHandler SomeEvent
{
add { mSomeEvent += value; }
remove { mSomeEvent -= value; }
}
private void RaiseSomeEvent()
{
var handler = mSomeEvent;
if( handler != null ) handler( this, EventArgs.Empty );
}
private EventHandler mSomeEvent;
Notice that if you want to raise the event you have to refer to the backing field. You can no longer do it using the event name itself. You could actually do this for INotifyPropertyChange
without resorting to an explicit implementation.
When you implement an interface explicitly you actually create "private" versions of the interface members. Now, I put private in quotes because the implementation is not actually private. The implementation is only accessible if the cast is accessed from the interface type. That's a bit of a mouthful, so here's an example:
public interface IFoo
{
int Bar { get; }
}
public class A : IFoo
{
int IFoo.Bar
{
get { return -1; }
}
}
Now, let's say we have the following in a method somewhere:
var a = new A();
int bar = a.Bar;
This will generate a compile error, because the type A
doesn't have a publically visible member called Bar
. However, if we cast to IFoo
first:
var a = new A();
int bar = ((IFoo) a).Bar;
Now it compiles and when it runs, bar == -1
. You could also have strongly typed the variable a
as IFoo
as well:
IFoo a = new A();
int bar = a.Bar;
That would also work. So this member can be accessed from outside the class (and even outside the assembly), but only directly through the declaring interface type. This can be useful to hide implementation you don't want to support (like the mutable parts of IList<T>
) or if you have different implementations depending on the interface, like GetEnumerator()
in IEnumerable
as opposed to the GetEnumerator()
in IEnumerable<T>
.
public class B : IFoo
{
public int Bar { get { return 2; } }
int IFoo.Bar { get { return 1; } }
}
Now if we use this class like so:
B b = new B();
IFoo bAsIFoo = b;
int barFromB = b.Bar;
int barFromFoo = bAsIFoo.Bar;
What you'll get here is barFromB == 2
and barFromFoo == 1
.
Upvotes: 3