DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Comprehensive Guide to Property-Based Testing in Go: Principles and Implementation
  • Implement Hibernate Second-Level Cache With NCache
  • Modify JSON Data in Postgres and Hibernate 6
  • Top 10 C# Keywords and Features

Trending

  • Building AI-Powered Java Applications With Jakarta EE and LangChain4j
  • 7 Technology Waves I’ve Seen in 30 Years of Software — Will AI Be the Next Real Transformation?
  • The Agentic Agile Office: Streamlining Enterprise Agile With Autonomous AI Agents
  • Good Data, Bad Metric: A Mutation Testing Pattern for Analytics Engineering

Implementing INotifyPropertyChanged

In article, a web development guru walks us through how we can use INotifyPropertyChanged to craft code that adheres to the DRY concept of programming.

By 
Gunnar Peipman user avatar
Gunnar Peipman
·
Apr. 03, 19 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
11.2K Views

Join the DZone community and get the full member experience.

Join For Free

This is a short post about how to implement INotifyPropertyChanged without using any advanced tooling. I have some small UWP applications where I'm using MVVM to separate presentation and logic. Here is how I use INotifyPropertyChanged with a base class for multiple view models.

First, one's introduction to INotifyPropertyChanged comes usually through some existing view model. The interface is used to communicate to the view that some properties in the view model have changed. Take a look at thePropertyChanged event and theNotifyPropertyChanged method (this method is not part of the interface).

public class GalleryViewModel : INotifyPropertyChanged
{
    public ObservableCollection<GalleryItem> Items { get; set; }

    public GalleryViewModel()
    {
        Items = new ObservableCollection<GalleryItem>();
        OpenImage = new RelayCommand<GalleryItem>(a => { SelectedItem = a; });
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private GalleryItem _selectedItem;

    public GalleryItem SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            NotifyPropertyChanged();
            NotifyPropertyChanged("SelectedItemVisibility");
            NotifyPropertyChanged("ListVisibility");
        }
    }

    public Visibility SelectedItemVisibility
    {
        get
        {
            return _selectedItem == null ? Visibility.Collapsed : Visibility.Visible;
        }
        set { }
    }

    public Visibility ListVisibility
    {
        get
        {
            return _selectedItem != null ? Visibility.Collapsed : Visibility.Visible;
        }
        set { }
    }

    public async Task LoadData()
    {
        var service = new GalleryService();
        var items = await service.LoadItems(null);


        foreach(var item in items)
        {
            Items.Add(item);
        }
    }

    public RelayCommand<GalleryItem> OpenImage { get; internal set; }
}

For the PropertyChanged method, there are many implementations. Jeremy Bytes's blog has an excellent overview of the evolution of INotifyPropertyChanged for those who want to find out more. Here, I will stick with what I have in the sample model above.

NotifyPropertyChanged Method

I have the shortest version of this method that I found. It works with newer .NET Frameworks.

public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

For those who find it tricky or weird, I'll give a few words for explanation.

CallerMemberName attribute is for the compiler. When the propertyName argument is not given to the method call, then the name of the calling method or property is set to propertyName. These two calls to the NotifyPropertyChanged() method are equal:

public GalleryItem SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        NotifyPropertyChanged();
        NotifyPropertyChanged("SelectedItem");
    }
}

But why this kind of shortcut? What it is good for? Although my sample model above fires the change of three properties it's not too common. Very often, we need to fire just one change event and it goes for the current property that changed. This is why this shortcut is good: we don't have to write the property name as a string and our code works even when the property name is changed.

NotifyPropertyChangedBase

Repeating the INotifyPropertyChanged event and method to fire this event to every single view model doesn't make much sense. We get a load of repeated code and if we want to change something we have to modify all copies of the repeated code. To avoid this, I wrote a NotifyPropertyChangedBase class.

public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Now we have a PropertyChanged event and NotifyPropertyChanged() method in a separate base class and we don't have to duplicate the code to all view models. Using this base class I can write the view model above like shown here.

public class GalleryViewModel : NotifyPropertyChangedBase
{
    public ObservableCollection<GalleryItem> Items { get; set; }

    public GalleryViewModel()
    {
        Items = new ObservableCollection<GalleryItem>();
        OpenImage = new RelayCommand<GalleryItem>(a => { SelectedItem = a; });
    }      

    private GalleryItem _selectedItem;

    public GalleryItem SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            NotifyPropertyChanged();
            NotifyPropertyChanged("SelectedItemVisibility");
            NotifyPropertyChanged("ListVisibility");
        }
    }

    public Visibility SelectedItemVisibility
    {
        get
        {
            return _selectedItem == null ? Visibility.Collapsed : Visibility.Visible;
        }
        set { }
    }

    public Visibility ListVisibility
    {
        get
        {
            return _selectedItem != null ? Visibility.Collapsed : Visibility.Visible;
        }
        set { }
    }

    public async Task LoadData()
    {
        var service = new GalleryService();
        var items = await service.LoadItems(null);


        foreach(var item in items)
        {
            Items.Add(item);
        }
    }

    public RelayCommand<GalleryItem> OpenImage { get; internal set; }
}

From here we can go even further and use frameworks like Prism or MVVM Light Toolkit to have most of the important base classes and MVVM features out-of-box.

Wrapping Up

Implementing INotifyPropertyChanged manually is not hard. Newer versions of C# provide us with the CallerMemberName ttributea and calls the method to fire events for property changes that get even smaller. Plus we don't have to write property names as strings. To avoid repeating INotifyPropertyChanged code to all view models, we created a simple base class and made our model extend it. We can also write the more general ViewModelBase that offers more functionalities that view models may need.

View model Property (programming)

Published at DZone with permission of Gunnar Peipman. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Comprehensive Guide to Property-Based Testing in Go: Principles and Implementation
  • Implement Hibernate Second-Level Cache With NCache
  • Modify JSON Data in Postgres and Hibernate 6
  • Top 10 C# Keywords and Features

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook