64

Is there a way to use INotifyPropertyChanged with auto-properties? Maybe an attribute or something other, not obvious to me.

public string Demo{
    get;set;
}

For me, auto-properties would be an extremely practicall thing, but almost always, I have to raise the PropertyChanged-event if the property value has been changed and without a mechanism to do this, auto-properties are useless for me.

HCL
  • 36,053
  • 27
  • 163
  • 213
  • Definitely nothing out of the box. Auto properties are also useless if you need to set a default value. – devuxer Jul 27 '10 at 19:50
  • 6
    For default value I did this in .NET 4.6 public string MyPropertyName { get; set; } = "My default value."; – pdschuller May 22 '18 at 18:59

6 Answers6

23

In .NET 4.5 and higher it can be made somewhat shorter:

private int unitsInStock;
public int UnitsInStock
{
    get { return unitsInStock; }
    set { SetProperty(ref unitsInStock, value);}
}
crea7or
  • 4,421
  • 2
  • 26
  • 37
  • 1
    I've been looking at this problem recently and almost came up with an identical solution although I didn't think to pass the member variable by reference. Very elegant, here's a gist of what I use : https://gist.github.com/SuperEvenSteven/2c02d988b2b1ba78c1ff70f9941948bd – JavaJedi Sep 26 '17 at 06:35
  • I now use in .Net Core 6 :) – Tim Davis Feb 16 '23 at 16:33
12

It's something you would have to code yourself. The closest you could get would be something like this implementation on Code Project that uses a custom attribute and aspect orientated methods to give this syntax:

[NotifyPropertyChanged] 
public class AutoWiredSource
{ 
   public double MyProperty { get; set; } 
}

Someone once proposed on Microsoft Connect a change to the C# specification implement this:

class Person : INotifyPropertyChanged
{
    // "notify" is a context keyword, same as "get" and "set"
    public string Name { get; set; notify; }
}

But the proposal has been now closed.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
  • Hmmmm, my first thought is that's a great idea. But I wonder how well it'd really hold up if implemented. – Matt Greer Jul 27 '10 at 19:47
  • @Matt - I'm not sure either, but when I was looking for the attribute example I came across it and thought I'd share. – ChrisF Jul 27 '10 at 19:49
  • I'm not sure what I'd think of this...while convenient, I'd prefer to keep the library components out of the language. An obvious exception is the `using` block, but what happens if (when) we come up with a different method of notifying property changes? – Adam Robinson Jul 28 '10 at 00:42
  • @Adam - I suspect that's one reason why the proposed change is just that. I think I prefer the attribute mechanism myself. – ChrisF Jul 28 '10 at 10:01
  • Download source code (1,225 KB)>> link not working – Vitaliy Mar 25 '23 at 16:29
10

There's no built-in mechanism to do this. Something like PostSharp would likely be able to add something like this for you (or Mark Gravell's HyperDescriptor, if you're just interested in making this databinding-aware).

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • 3
    And there is Fody.PropertyChanged https://github.com/Fody/PropertyChanged (Injects code which raises the PropertyChanged event, into property setters of classes which implement INotifyPropertyChanged) This doesn't require applying any attributes but also takes away some of your control over the process. – TimothyP Sep 27 '17 at 02:38
3

INotifyPropertyChanged and DependencyProperties have certainly made properties a lot less fun. The best solution I've found is good snippets. Such as the ones that come in the Silverlight contrib project

Matt Greer
  • 60,826
  • 17
  • 123
  • 123
3

I tried other ways first using:

Those methods work, however I've still had to muddy the accessor methods of all properties in the Model or use a dynamic object which kills your auto-completion when coding. It's also worth mentioning that WinForms don't support binding to dynamic objects unfortunately.

Solution

Eventually I came across ReactiveUI.Fody. It's a simple to use solution using Fody and ReactiveUI. I used this in my WPF project successfully.

It weaves in the required boilerplate code, RaisePropertyChanges and ObservableAsPropertyHelper, at compile time.

Project Dependencies

https://github.com/kswoll/ReactiveUI.Fody

I installed the following packages in my project with NuGet:

<packages>
  <package id="Fody" version="2.0.7" targetFramework="net452" developmentDependency="true" />
  <package id="reactiveui" version="7.4.0" targetFramework="net452" />
  <package id="ReactiveUI.Fody" version="2.2.11" targetFramework="net452" />
  <package id="reactiveui-core" version="7.4.0" targetFramework="net452" />
  <package id="Rx-Core" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Interfaces" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Linq" version="2.2.5" targetFramework="net452" />
  <package id="Rx-Main" version="2.2.5" targetFramework="net452" />
  <package id="Rx-PlatformServices" version="2.2.5" targetFramework="net452" />
  <package id="Rx-XAML" version="2.2.5" targetFramework="net452" />
  <package id="Splat" version="1.6.0" targetFramework="net452" />
</packages>

Fody Setup

You'll need to create a FodyWeavers.xml file in the top level of you project so it looks like this:

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

Usage

You just set your Model classes to inherit off ReactiveObject and add the [Reactive] attribute above any property you want to notify of changes.

using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace name.domain.some{
    class SomeClass : ReactiveObject {
        [Reactive]
        public string SomeProperty { get; set; }
    }
}

Job done! Rebuild your project and check the output window in Visual Studio. You should see some lines outputted from Fody as it processes your annotated Model classes and injects the appropriate boilerplate code. It should look something like this:

enter image description here

Further Info

More useful info can be found here.

JavaJedi
  • 399
  • 3
  • 7
1

Useful answer by crea7or, ended up using it in my latest project. One way to improve it is by rewriting SetProperty this way:

protected bool SetProperty<T>(ref T storage, T value, string[] dependentPropertyNames = null, [CallerMemberName] string propertyName = null)
{
    if (Equals(storage, value))
    {
        return false;
    }

    storage = value;
    this.OnPropertyChanged(propertyName);

    if(dependentPropertyNames != null)
    {
        foreach(var dependentPropertyName in dependentPropertyNames)
        {
            OnPropertyChanged(dependentPropertyName);
        }
    }

    return true;
}

It now allows to pass in dependent property names allowing view to know that dependent property value has changed even though it was not set directly, but as a result of other properties being set.

Usage:

private string firstName;
public string FirstName
{
    get { return firstName; }
    set { SetProperty(ref firstName, value, new[] { "FullName" }); }
}

private string lastName;
public string LastName
{
    get { return lastName; }
    set { SetProperty(ref lastName, value, new[] { "FullName" }); }
}

public string FullName
{
    get { return $"{FirstName} {LastName}"; }
}
Maz T
  • 1,184
  • 13
  • 18