Automatically Inotifypropertychanged

Automatic INotifyPropertyChanged after change in View

Okay, I'll leave an answer instead of a slightly cryptic comment (which I did because you actually learn better if you discover the answer yourself rather than being spoonfed...).

The previous link you left states:

And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.

(Emphasis mine. For the sake of completion, here is the link that was left with that answer: MSDN forums: Data binding without INotifyPropertyChanged).

Previously you had relied on the default behavior of WPF, but when you implement INotifyPropertyChanged you are effectively saying "Yo WPF!! I want to be really specific and particular about what gets notified, so that default behavior can take a seat at the back!". You then failed to add a notification on the Text property. So as per your coding decision, WPF binding no longer detects property changes in that class unless you specifically trigger them.

Personally I always implement INotifyPropertyChanged because then property changes are still notified even when the value is changed via code (because the PropertyDescriptor used by default doesn't detect this). Additionally it gives me the flexibility to not notify, or to notify several properties if one changes.

INotifyPropertyChanged and Auto-Properties

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).

MVVM INotifyPropertyChanged with Automatic Property Name implementation

The Problem with using the StackTrace is, that it is not properly populated in release builds. To overcome this issue there are several approaches to fix it and make raising the PropertyChanged event easier for developers.

See this question: Implementing INotifyPropertyChanged - does a better way exist? and pick a solution that suits you :)

Personally I prefer the following:

// Helper method
public static PropertyChangedEventArgs CreateArguments<TOwner>(Expression<Func<TOwner, object>> Expression) {
// determine the Name of the property using the Expression
}

// Within the view-model implementations:
private static readonly PropertyChangedEventArgs TitleProperty = CreateArguments<MyViewModel>(m => m.Title);

private string title;

public string Title {
get { return this.title; }
set {
if (!string.Equals(this.title, value) {
this.title = value;
this.OnPropertyChanged(TitleProperty);
}
}
}

By using a static member to pre-generate the PropertyChangedEventArgs, the overhead introduced by inspecting the expression tree is limited. This solution is re-factor safe, so you don't have any magic strings.

I also like the .NET 4.5 Approach using the CallerMemberNameAttribute, but It seems that it doesn't work in Portable Class Libraries.

INotifyPropertyChanged-Feature on Auto-Properties

Try Fody. It is library which modifies IL code during build process using dedicated msbuild task.

It has large base of addins including PropertyChanged which should suit in your scenario.
This addin gives you attribute ImplementPropertyChanged which you can apply to a class. Then Fody will generate code implementing INotifyPropertyChanged to all auto-properties.

Second option if you have ReSharper version 7 or higher. It has refactoring which can help you with implementation of INotifyPropertyChanges. For example it can transform auto-property to "normal" property implementing the interface.
Thou it may not fully satisfy you - this approach may be interesting for you because it does not involve additional libraries and assembly modification.

INotifyPropertyChanged on all properties

Add a method that looks like this:

public void Test()
{
if(PropertyChanged != null)
PropertyChanged(new PropertyChangedEventArgs(null));
}

Passing a null or empty string as the property name tells consumers that all properties have been changed.

https://msdn.microsoft.com/en-us/library/system.componentmodel.propertychangedeventargs.propertyname(v=vs.110).aspx

Implementing INotifyPropertyChanged - does a better way exist?

Without using something like postsharp, the minimal version I use uses something like:

public class Data : INotifyPropertyChanged
{
// boiler-plate
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}

// props
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}
}

Each property is then just something like:

private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}

which isn't huge; it can also be used as a base-class if you want. The bool return from SetField tells you if it was a no-op, in case you want to apply other logic.


or even easier with C# 5:

protected bool SetField<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{...}

which can be called like this:

set { SetField(ref name, value); }

with which the compiler will add the "Name" automatically.


C# 6.0 makes the implementation easier:

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

...and now with C#7:

protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

protected bool SetField<T>(ref T field, T value,[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}

private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}

And, with C# 8 and Nullable reference types, it would look like this:

public event PropertyChangedEventHandler? PropertyChanged;

protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}

private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}

Automatic INotifyPropertyChanged Implementation through T4 code generation?

Here's a great post by Colin Eberhardt on generating Dependency Properties from a T4 by inspecting custom attributes directly from Visual Studio with EnvDTE. It shouldn't be difficult to adapt it to inspect fields and generate code appropriately since the post contains simple utility methods to browse code nodes.

Note that when using T4 from VS, you shouldn't use Reflection on your own assemblies or they'll get locked and you'll have to restart Visual Studio in order to rebuild.

Understanding INotifyPropertyChanged

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.

OnPropertyChanged("NameFromClassA") is typically implemented in the BaseViewModel Class and is equivalent to doing :

    if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("NameFromClassA"));

It tells whoever is listening to the PropertyChanged event of your Demo Class that a Property named "NameFromClassA" has changed value (your example is wrong because there's no such Property in your Class).

It's required for DependencyProperties bound to Properties of your VM to update themselves and is rarely used for anything else.


Edit:

Psoeudo-code of what's roughly equivalent to what the binding engine does behind the scene :

ClassA myClassA;
string myPropertyBoundToNameOfClassA;

// somewhere after myClassA was initialized
myClassA.PropertyChanged += OnMyClassAPropertyChanged;

void MyClassAPropertyChanged(string name)
{
if (name == "NameFromClassA")
myPropertyBoundToNameOfClassA = myClassA.Name;
}


Related Topics



Leave a reply



Submit