• Blog
  • Info Support
  • Career
  • Training
  • International Group
  • Info Support
  • Blog
  • Career
  • Training
  • International Group
  • Search
logo InfoSupport
  • Latest blogs
  • Popular blogs
  • Experts
      • Alles
      • Bloggers
      • Speakers
  • Meet us
  • About us
    • nl
    • en
    • .NET
    • Advanced Analytics
    • Agile
    • Akka
    • Alexa
    • Algorithms
    • Api's
    • Architectuur
    • Artificial Intelligence
    • ATDD
    • Augmented Reality
    • AWS
    • Azure
    • Big Data
    • Blockchain
    • Business Intelligence
    • Cloud
    • Code Combat
    • Cognitive Services
    • Communicatie
    • Containers
    • Continuous Delivery
    • CQRS
    • Cyber Security
    • Dapr
    • Data
    • Data & Analystics
    • Data Science
    • Data Warehousing
    • Databricks
    • DevOps
    • Digital Days
    • Docker
    • eHealth
    • Enterprise Architecture
    • Hacking
    • Infrastructure & Hosting
    • Innovatie
    • Integration
    • Internet of Things
    • Java
    • Machine Learning
    • Microservices
    • Microsoft
    • Microsoft Bot Framework
    • Microsoft Data Platform
    • Mobile Development
    • Mutation Testing
    • Open source
    • Pepper
    • Power BI
    • Privacy & Ethiek
    • Python
    • Quality Assistance & Test
    • Quality Assurance & Test
    • Requirements Management
    • Scala
    • Scratch
    • Security
    • SharePoint
    • Software Architecture
    • Software development
    • Software Factory
    • SQL Server
    • SSL
    • Start-up
    • Startup thinking
    • Stryker
    • Test Quality
    • Testing
    • TLS
    • TypeScript
    • Various
    • Web Development
    • Web-scale IT
    • Xamarin
    • Alles
    • Bloggers
    • Speakers
Home » Implementing INotifyPropertyChanged
  • Implementing INotifyPropertyChanged

    • By Erno de Weerd
    • Various 12 years ago
    • Various 0 comments
    • Various Various
    Implementing INotifyPropertyChanged

    One of the things you do regularly when working with Silverlight and/or WPF is implementing INotifyPropertyChanged.

    image

    In short: this interface exposes an event (PropertyChanged) that is raised when a property of the object changes its value. This allows other parts of your application to respond to changes in the class that implements the interface. For instance: a TextBlock shows the value of the Name property of a Person object and you want the TextBlock to update the text as soon as the Name property changes its value. So the Text property of the TextBlock need to be notified of changes to the Name property of the Person.

    Here is a very basic implementation of the Person class:

     1: public class Person : INotifyPropertyChanged

     

     2: {

     

     3:     private string _name;

     

     4:

     

     5:     public string Name

     

     6:     {

     

     7:         get { return _name; }

     

     8:         set

     

     9:         {

     

     10:             _name = value;

     

     11:             if (PropertyChanged != null)

     

     12:             {

     

     13:                 PropertyChanged(this, new PropertyChangedEventArgs("Name"));

     

     14:             }

     

     15:         }

     

     16:     }

     

     17:     public event PropertyChangedEventHandler PropertyChanged;

     

     18: }

     

    As you can see in lines 11-14: if at least a single object subscribed to the PropertyChanged event the class raises the event passing itself as the source and the name of the property that changed. BTW: notice that in order to have the event raised you should use the property setter when writing to the property and not the field (_name) unless you want to suppress the event.

    There a  couple of things wrong with this implementation. I’ll fix them one by one.

    First: when there are more properties we need to repeat the same code over and over in the setters so let’s factor out the raising of the event:

     1: public class Person : INotifyPropertyChanged

     

     2: {

     

     3:     private string _name;

     

     4:

     

     5:     public string Name

     

     6:     {

     

     7:         get { return _name; }

     

     8:         set

     

     9:         {

     

     10:             _name = value;

     

     11:             OnPropertyChanged("Name");

     

     12:         }

     

     13:     }

     

     14:

     

     15:     protected void OnPropertyChanged(string propertyName)

     

     16:     {

     

     17:         if (PropertyChanged != null)

     

     18:         {

     

     19:             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

     

     20:         }

     

     21:     }

     

     22:     public event PropertyChangedEventHandler PropertyChanged;

     

     23: }

     

    The protected OnPropertyChanged method raises the event and can easily be called from within any setter in the class and its descendants.

    Now a tricky error in this implementation. Suppose that between lines 17 and 19 the last subscriber to the event unregisters. This would clear the event’s invocation list and would cause a null reference exception in line 19. To make the method thread-safe we use the following construction:

     1: protected void OnPropertyChanged(string propertyName)

     

     2: {

     

     3:     PropertyChangedEventHandler p = PropertyChanged;

     

     4:     if (p != null)

     

     5:     {

     

     6:         p(this, new PropertyChangedEventArgs(propertyName));

     

     7:     }

     

     8: }

     

    It isn’t that obvious that this solves the concurrency problem. But it does. Here is how: the invocation list is immutable so as soon as there is a change to the list (someone registers or unregisters) a NEW list is created. So when we first copy (p in line 3) the reference, both references point to the same invocation list but when an object (un)registers the event will point to a different list but the copy still contains the original list.

    On to the next problem. As you can see we specify the name of the changed property in the call to the OnPropertyChanged method as a literal string. This can cause problems when making spelling errors or when renaming the property without updating the literal string. Even worse: it fails silently.

     

     1: public string FirstName

     

     2: {

     

     3:     get { return _firstName; }

     

     4:     set

     

     5:     {

     

     6:         _firstName = value;

     

     7:         OnPropertyChanged("Name");

     

     8:     }

     

     9: }

     

    Although the event is raised it will communicate the wrong property name to the event subscriber.

    So let’s solve this by using reflection:

     1: public string Name

     

     2: {

     

     3:     get { return _name; }

     

     4:     set

     

     5:     {

     

     6:         _name = value;

     

     7:         OnPropertyChanged(MethodInfo.GetCurrentMethod().Name.Substring(4));

     

     8:     }

     

     9: }

     

    The setter is a method that is prefixed with “set_” so that is why we cut off those first four characters.

    This seems fine and it does work however we now pay a penalty due to the fact that reflection is slow. So let’s add an optimization:

     1: public string Name

     

     2: {

     

     3:     get { return _name; }

     

     4:     set

     

     5:     {

     

     6:         if (_name != value)

     

     7:         {

     

     8:             _name = value;

     

     9:             OnPropertyChanged(MethodInfo.GetCurrentMethod().Name.Substring(4));

     

     10:         }

     

     11:     }

     

     12: }

     

    This way (line 6) we only raise the event when there really is a change of the value. This addition is an optimization that is a good idea even when we do not use reflection.  Now let’s try to get rid of the reflection:

     1: public string Name

     

     2: {

     

     3:     get { return _name; }

     

     4:     set

     

     5:     {

     

     6:         if (_name != value)

     

     7:         {

     

     8:             string propertyName = "Name";

     

     9:             Debug.Assert(

     

     10:               propertyName == MethodInfo.GetCurrentMethod().Name.Substring(4),

     

     11:               String.Format("Error in property setter: {0}",

     

     12:                 MethodInfo.GetCurrentMethod().Name.Substring(4));

     

     13:             _name = value;

     

     14:             OnPropertyChanged(propertyName);

     

     15:         }

     

     16:     }

     

     17: }

     

    The Debug comes to the rescue: Assert and its parameters will only be evaluated and called when running the Debug version of the assembly is being executed. So this solution requires unit tests to make sure that the assertions are evaluated before building the release version.

    When renaming the property and forgetting to change line 8 with the correct value an exception will be thrown when running the debug build version.

    Our simple property has grown quite a bit and now requires a lot of typing. I see two valid solutions for that:

    1. An item template for a class that implements INotifyPropertyChanged and a snippet for a property that raises the PropertyChanged event.
    2. Code generation using a tool or T4 templates (I might add a post on that later)

    I picked the first option for the time being. My template:

    using System;

     

    using System.ComponentModel;

     

    using System.Diagnostics;

     

    using System.Reflection;

     

    
    

     

    namespace $rootnamespace$

     

    {

     

        public class $safeitemname$ : INotifyPropertyChanged

     

        {

     

    
    

     

            #region INotifyPropertyChanged Implementation

     

            public event PropertyChangedEventHandler PropertyChanged;

     

            protected void OnPropertyChanged(string propertyName)

     

            {

     

                PropertyChangedEventHandler p = PropertyChanged;

     

                if (p != null)

     

                {

     

                    p(this, new PropertyChangedEventArgs(propertyName));

     

                }

     

            }

     

            private static readonly string ERROR_PROP_NOT_FOUND = "Property name {0} not found.n" +

     

                "Possible cause: renaming the property {1}.{2} from {0} to {2} without " +

     

                "updating the value of the propertyName variable in setter.";

     

            #endregion

     

        }

     

    }

     

    And the snippet:

    <?xml version="1.0" encoding="utf-8"?>

    &nbsp;

    <CodeSnippets >="http://schemas.microsoft.com/VisualStudio/2008/CodeSnippet">

    &nbsp;

      <CodeSnippet Format="1.0.0">

    &nbsp;

    
    

    &nbsp;

        <Header>

    &nbsp;

          <Title>Property Changed</Title>

    &nbsp;

          <Description>Insert Property that supports INotifyPropertyChanged</Description>

    &nbsp;

          <Shortcut>proppc</Shortcut>

    &nbsp;

        </Header>

    &nbsp;

        <Snippet>

    &nbsp;

          <Declarations>

    &nbsp;

            <Literal>

    &nbsp;

              <ID>type</ID>

    &nbsp;

              <ToolTip>Property type</ToolTip>

    &nbsp;

              <Default>int</Default>

    &nbsp;

            </Literal>

    &nbsp;

            <Literal>

    &nbsp;

              <ID>field</ID>

    &nbsp;

              <ToolTip>Field</ToolTip>

    &nbsp;

              <Default>myField</Default>

    &nbsp;

            </Literal>

    &nbsp;

            <Literal>

    &nbsp;

              <ID>property</ID>

    &nbsp;

              <ToolTip>Property name</ToolTip>

    &nbsp;

              <Default>MyProperty</Default>

    &nbsp;

            </Literal>

    &nbsp;

          </Declarations>

    &nbsp;

          <Code Language="CSharp">

    &nbsp;

            <![CDATA[#region $property$ Property

    &nbsp;

            private $type$ _$field$;

    &nbsp;

            public $type$ $property$

    &nbsp;

            {

    &nbsp;

              get

    &nbsp;

              {

    &nbsp;

                return _$field$;

    &nbsp;

              }

    &nbsp;

              set

    &nbsp;

              {

    &nbsp;

                if(_$field$ != value)

    &nbsp;

                {

    &nbsp;

                  string propertyName = "$property$";

    &nbsp;

                  Debug.Assert(

    &nbsp;

                    propertyName == MethodInfo.GetCurrentMethod().Name.Substring(4),

    &nbsp;

                    String.Format(ERROR_PROP_NOT_FOUND, propertyName,

    &nbsp;

                        this.GetType().Name,

    &nbsp;

                        MethodInfo.GetCurrentMethod().Name.Substring(4)));

    &nbsp;

                  _$field$ = value;

    &nbsp;

                  OnPropertyChanged(propertyName);

    &nbsp;

                }

    &nbsp;

              }

    &nbsp;

            }

    &nbsp;

            #endregion

    &nbsp;

            ]]>

    &nbsp;

          </Code>

    &nbsp;

        </Snippet>

    &nbsp;

      </CodeSnippet>

    &nbsp;

    </CodeSnippets>

    &nbsp;

    When adding a new class to a WPF or Silverlight application (e.g. when adding a class to the ViewModel in MVVM) I now get to pick a new template:

    image

    And when coding a property I use proppc:

    image

    I am quite happy with this. There are other concerns such as:

    • When updating the property a lot (animation) this code generates a lot of EventArgs objects littering the heap.
    • The check for the correct name is done only in the Debug build.

    Thoughts and solutions can be found here:

    • http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged
    • http://jeffhandley.com/archive/2008/10/07/inotifypropertychanged—-searching-for-a-better-way.aspx
    • http://thetreeknowseverything.wordpress.com/2009/01/21/auto-implement-inotifypropertychanged-with-aspects/
    • http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

    You can download my snippet and template here.

    Copy the snippet to: <drive>:Users<user>DocumentsVisual Studio 2010Code SnippetsVisual C#My Code Snippets

    Copy the zipped template to: <drive>:Users<user>DocumentsVisual Studio 2010TemplatesItemTemplatesVisual C#

    NB: Please also read my next post

    Share this

Erno de Weerd

View profile

IT Training at Info Support

Which training fits you?

Consultancy

Consultancy

Related blogs

  • Video Conferencing en OBS Studio koppelen: online prese…

    Video Conferencing en OBS Studio koppelen: online prese… Maaike Brouwer - 1 year ago

  • Verantwoordelijkheid pakken in jouw eigen persoonlijke …

    Verantwoordelijkheid pakken in jouw eigen persoonlijke … Stephan Versteegh - 1 year ago

  • Tips voor als je gaat afstuderen

    Tips voor als je gaat afstuderen Bart Renders - 2 years ago

Related downloads

  • Beslisboom voor een rechtmatig ‘kopietje productie’

  • Klantreferentie: Remmicom zet wetgeving om in intellige…

  • Klantreferentie RDW: Samenwerken voor veilig en vertrou…

  • Klantreferentie BeFrank: Strategische IT voor een innov…

  • Wie durft te experimenteren met data in de zorg?

Related videos

  • mijnverzekeringenopeenrij.nl

    mijnverzekeringenopeenrij.nl

  • Winnaar | Innovation Projects 2017

    Winnaar | Innovation Projects 2017

  • Explore | Info Support & HAN & Poliskluis

    Explore | Info Support & HAN & Poliskluis

  • LifeApps bij HagaZiekenhuis

    LifeApps bij HagaZiekenhuis

  • Info Support | Bedrijfsfilm

    Info Support | Bedrijfsfilm

Nieuwsbrief

* verplichte velden

Contact

  • Head office NL
  • Kruisboog 42
  • 3905 TG Veenendaal
  • T +31 318 552020
  • Call
  • Mail
  • Directions
  • Head office BE
  • Generaal De Wittelaan 17
  • bus 30 2800 Mechelen
  • T +32 15 286370
  • Call
  • Mail
  • Directions

Follow us

  • Twitter
  • Facebook
  • Linkedin
  • Youtube

Newsletter

Sign in

Extra

  • Media Library
  • Disclaimer
  • Algemene voorwaarden
  • ISHBS Webmail
  • Extranet
Beheer cookie toestemming
Deze website maakt gebruik van Functionele en Analytische cookies voor website optimalisatie en statistieken.
Functioneel
Altijd actief
De technische opslag of toegang is strikt noodzakelijk voor het legitieme doel het gebruik mogelijk te maken van een specifieke dienst waarom de abonnee of gebruiker uitdrukkelijk heeft gevraagd, of met als enig doel de uitvoering van de transmissie van een communicatie over een elektronisch communicatienetwerk.
Voorkeuren
De technische opslag of toegang is noodzakelijk voor het legitieme doel voorkeuren op te slaan die niet door de abonnee of gebruiker zijn aangevraagd.
Statistieken
De technische opslag of toegang die uitsluitend voor statistische doeleinden wordt gebruikt. De technische opslag of toegang die uitsluitend wordt gebruikt voor anonieme statistische doeleinden. Zonder dagvaarding, vrijwillige naleving door uw Internet Service Provider, of aanvullende gegevens van een derde partij, kan informatie die alleen voor dit doel wordt opgeslagen of opgehaald gewoonlijk niet worden gebruikt om je te identificeren.
Marketing
De technische opslag of toegang is nodig om gebruikersprofielen op te stellen voor het verzenden van reclame, of om de gebruiker op een website of over verschillende websites te volgen voor soortgelijke marketingdoeleinden.
Beheer opties Beheer diensten Beheer leveranciers Lees meer over deze doeleinden
Voorkeuren
{title} {title} {title}