I just wanted to add a couple of points to BradleyDotNET's answer.
In his book CLR via C#, Jeffrey Richter points out that the pattern is still not guaranteed to be thread-safe, because the compiler could optimize away the local variable (although the current version of the compiler does not make this optimization). He recommends using Volatile.Read
to be technically correct:
PropertyChangedEventHandler handler = Volatile.Read(ref PropertyChanged);
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
In reality though, the other pattern is so widely used that Microsoft would very likely never make a change to the compiler that would break so many applications.
One other point, is that you can actually add an empty dummy delegate to your events, like below:
public event PropertyChangedEventHandler PropertyChanged = delegate { };
This means you don't have to worry about any null checking, because the event has at least one handler attached to start with. This practice is controversial, though, since it would seem to incur a performance penalty (in theory you add an extra invocation to every event call). Personally I avoid using it, as I would rather suffer more bloated code than bloated runtime performance.
This blog post by Eric Lippert on the topic is a good read.