How to decompose expression to satisfy generic property change method? - c#

I have a base EF entity class which implements INotifyPropertyChanged.
The base property, Id is my example:
/// <summary>
/// Entity Id
/// </summary>
public int Id {
get { return id; }
set { SetValue<int>(() => (Id != value), (v) => id = v); } // < can this be simplified into a single call?
}
...where SetValue is defined:
protected void SetValue<TValue>(Expression<Func<bool>> evalExpr, Action<TValue> set) {
// Compile() returns a Func<bool>
var doSetValue = evalExpr.Compile();
if (doSetValue()) {
var expr = evalExpr.Body as BinaryExpression;
// this is not compiling - how do I decompose the expression to get what I need?
var propertyName = ((PropertyExpression)expr.Left).Name;
var assignValue = (TValue)((ConstantExpression)expr.Right).Value;
set(assignValue);
_propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
All samples I can find are expecting parameters. I prefer that the setter (SetValue call) is as simple as possible - i.e., is there a way to reduce the input parameter to 1?

You should change
var propertyName = ((PropertyExpression)expr.Left).Name;
to
var propertyName = ((MemberExpression)expr.Left).Member.Name;
and your code compiles, but what you are doing is not optimal and trustful at all. And you'll get an InvalidCastException!
Compiling an Expression<T> on every call is not optimal, and, how can you tell that the user passes the lambda to the method like:
() => (Id != value)
and not
() => (id != value) // using the field instead of property
or
() => (value != Id) // passing the property as the second operand
?
Also, value in your expression is not a ConstantExpression. The value itself is just a local variable to the set part of the property, and when passed to a lambda expression, is promoted to a class field (the value is captured - see here for more information). So what you have is a MemberExpression on both sides.
I highly recommend using this approach if you can't use .NET 4.5 ([CallerMemberName]):
public class EntityBase : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged(string propName)
{
var h = PropertyChanged;
if (h != null)
h(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
protected bool ChangeAndNofity<T>(ref T field, T value, Expression<Func<T>> memberExpression)
{
if (memberExpression == null)
{
throw new ArgumentNullException("memberExpression");
}
var body = memberExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("Lambda must return a property.");
}
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
OnPropertyChanged(body.Member.Name);
return true;
}
}
Using it is simple:
public class Person : EntityBase
{
private int _id;
public int Id
{
get { return _id; }
set { ChangeAndNofity(ref _id, value, () => Id); }
}
}

There are various options that are simpler than what you've got (here are a few in rough order of how well I like each one):
Fody/PropertyChanged - This is a free, automatic code weaver that runs at compile time to automagically implement INotifyPropertyChanged on the properties of the classes you choose. No assemblies required at runtime.
INotifyPropertyChanged, The .NET 4.5 Way – Revisited
PostSharp - Automatically implementing INotifyPropertyChanged
INotifyPropertyChanged Interface documentation's code sample
Here's the core code snippet from "The .NET 4.5 Way":
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
Used like:
/// <summary>
/// Entity Id
/// </summary>
public int Id {
get { return id; }
set { SetValue(ref id, value); }
}

Related

Is there a way to call a method on an auto property set? [duplicate]

Microsoft should have implemented something snappy for INotifyPropertyChanged, like in the automatic properties, just specify {get; set; notify;}
I think it makes a lot of sense to do it. Or are there any complications to do it?
Can we ourselves implement something like 'notify' in our properties. Is there a graceful solution for implementing INotifyPropertyChanged in your class or the only way to do it is by raising the PropertyChanged event in each property.
If not can we write something to auto-generate the piece of code to raise PropertyChanged event?
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);
}
As of .Net 4.5 there is finally an easy way to do this.
.Net 4.5 introduces a new Caller Information Attributes.
private void OnPropertyChanged<T>([CallerMemberName]string caller = null) {
// make sure only to call this if the value actually changes
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(caller));
}
}
It's probably a good idea to add a comparer to the function as well.
EqualityComparer<T>.Default.Equals
More examples here and here
Also see Caller Information (C# and Visual Basic)
I really like Marc's solution, but I think it can be slightly improved to avoid using a "magic string" (which doesn't support refactoring). Instead of using the property name as a string, it's easy to make it a lambda expression :
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, () => Name); }
}
Just add the following methods to Marc's code, it will do the trick :
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(selectorExpression);
return true;
}
BTW, this was inspired by this blog post.
There's also Fody which has a AddINotifyPropertyChangedInterface add-in, which lets you write this:
[AddINotifyPropertyChangedInterface]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
}
...and at compile time injects property changed notifications.
I think people should pay a little more attention to performance; it really does impact the UI when there are a lot of objects to be bound (think of a grid with 10,000+ rows), or if the object's value changes frequently (real-time monitoring app).
I took various implementation found here and elsewhere and did a comparison; check it out perfomance comparison of INotifyPropertyChanged implementations.
Here is a peek at the result
I introduce a Bindable class in my blog at http://timoch.com/blog/2013/08/annoyed-with-inotifypropertychange/
Bindable uses a dictionary as a property bag. It's easy enough to add the necessary overloads for a subclass to manage its own backing field using ref parameters.
No magic string
No reflection
Can be improved to suppress the default dictionary lookup
The code:
public class Bindable : INotifyPropertyChanged {
private Dictionary<string, object> _properties = new Dictionary<string, object>();
/// <summary>
/// Gets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
protected T Get<T>([CallerMemberName] string name = null) {
Debug.Assert(name != null, "name != null");
object value = null;
if (_properties.TryGetValue(name, out value))
return value == null ? default(T) : (T)value;
return default(T);
}
/// <summary>
/// Sets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
/// <remarks>Use this overload when implicitly naming the property</remarks>
protected void Set<T>(T value, [CallerMemberName] string name = null) {
Debug.Assert(name != null, "name != null");
if (Equals(value, Get<T>(name)))
return;
_properties[name] = value;
OnPropertyChanged(name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
It can be used like this:
public class Contact : Bindable {
public string FirstName {
get { return Get<string>(); }
set { Set(value); }
}
}
I haven't actually had a chance to try this myself yet, but next time I'm setting up a project with a big requirement for INotifyPropertyChanged I'm intending on writing a Postsharp attribute that will inject the code at compile time. Something like:
[NotifiesChange]
public string FirstName { get; set; }
Will become:
private string _firstName;
public string FirstName
{
get { return _firstname; }
set
{
if (_firstname != value)
{
_firstname = value;
OnPropertyChanged("FirstName")
}
}
}
I'm not sure if this will work in practice and I need to sit down and try it out, but I don't see why not. I may need to make it accept some parameters for situations where more than one OnPropertyChanged needs to be triggered (if, for example, I had a FullName property in the class above)
Currently I'm using a custom template in Resharper, but even with that I'm getting fed up of all my properties being so long.
Ah, a quick Google search (which I should have done before I wrote this) shows that at least one person has done something like this before here. Not exactly what I had in mind, but close enough to show that the theory is good.
Yes, better way certainly exists.
Here it is:
Step by step tutorial shrank by me, based on this useful article.
Create new project
Install castle core package into the project
Install-Package Castle.Core
Install mvvm light libraries only
Install-Package MvvmLightLibs
Add two classes in project:
NotifierInterceptor
public class NotifierInterceptor : IInterceptor
{
private PropertyChangedEventHandler handler;
public static Dictionary<String, PropertyChangedEventArgs> _cache =
new Dictionary<string, PropertyChangedEventArgs>();
public void Intercept(IInvocation invocation)
{
switch (invocation.Method.Name)
{
case "add_PropertyChanged":
handler = (PropertyChangedEventHandler)
Delegate.Combine(handler, (Delegate)invocation.Arguments[0]);
invocation.ReturnValue = handler;
break;
case "remove_PropertyChanged":
handler = (PropertyChangedEventHandler)
Delegate.Remove(handler, (Delegate)invocation.Arguments[0]);
invocation.ReturnValue = handler;
break;
default:
if (invocation.Method.Name.StartsWith("set_"))
{
invocation.Proceed();
if (handler != null)
{
var arg = retrievePropertyChangedArg(invocation.Method.Name);
handler(invocation.Proxy, arg);
}
}
else invocation.Proceed();
break;
}
}
private static PropertyChangedEventArgs retrievePropertyChangedArg(String methodName)
{
PropertyChangedEventArgs arg = null;
_cache.TryGetValue(methodName, out arg);
if (arg == null)
{
arg = new PropertyChangedEventArgs(methodName.Substring(4));
_cache.Add(methodName, arg);
}
return arg;
}
}
ProxyCreator
public class ProxyCreator
{
public static T MakeINotifyPropertyChanged<T>() where T : class, new()
{
var proxyGen = new ProxyGenerator();
var proxy = proxyGen.CreateClassProxy(
typeof(T),
new[] { typeof(INotifyPropertyChanged) },
ProxyGenerationOptions.Default,
new NotifierInterceptor()
);
return proxy as T;
}
}
Create your view model, for example:
-
public class MainViewModel
{
public virtual string MainTextBox { get; set; }
public RelayCommand TestActionCommand
{
get { return new RelayCommand(TestAction); }
}
public void TestAction()
{
Trace.WriteLine(MainTextBox);
}
}
Put bindings into xaml:
<TextBox Text="{Binding MainTextBox}" ></TextBox>
<Button Command="{Binding TestActionCommand}" >Test</Button>
Put line of code in code-behind file MainWindow.xaml.cs like this:
DataContext = ProxyCreator.MakeINotifyPropertyChanged<MainViewModel>();
Enjoy.
Attention!!! All bounded properties should be decorated with
keyword virtual because they used by castle proxy for overriding.
A very AOP-like approach is to inject the INotifyPropertyChanged stuff onto an already instantiated object on the fly. You can do this with something like Castle DynamicProxy. Here is an article that explains the technique:
Adding INotifyPropertyChanged to an existing object
It's 2022. Now there's an official solution.
Use the MVVM source generators in Microsoft MVVM Toolkit.
This
[ObservableProperty]
private string? name;
will generate:
private string? name;
public string? Name
{
get => name;
set
{
if (!EqualityComparer<string?>.Default.Equals(name, value))
{
OnNameChanging(value);
OnPropertyChanging();
name = value;
OnNameChanged(value);
OnPropertyChanged();
}
}
}
// Property changing / changed listener
partial void OnNameChanging(string? value);
partial void OnNameChanged(string? value);
protected void OnPropertyChanging([CallerMemberName] string? propertyName = null)
{
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
}
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
It supports .NET standard 2.0 and .NET >= 5.0.
Look here : http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
It's written in German, but you can download the ViewModelBase.cs. All the comments in the cs-File are written in English.
With this ViewModelBase-Class it is possible to implement bindable properties similar to the well known Dependency Properties :
public string SomeProperty
{
get { return GetValue( () => SomeProperty ); }
set { SetValue( () => SomeProperty, value ); }
}
Let me introduce my own approach called Yappi.
It belongs to Runtime proxy|derived class generators, adding new functionality to an existing object or type, like Caste Project's Dynamic Proxy.
It allows to implement INotifyPropertyChanged once in base class, and then declare derived classes in following style, still supporting INotifyPropertyChanged for new properties:
public class Animal:Concept
{
protected Animal(){}
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
Complexity of derived class or proxy construction can be hidden behind the following line:
var animal = Concept.Create<Animal>.New();
And all INotifyPropertyChanged implementation work can be done like this:
public class Concept:INotifyPropertyChanged
{
//Hide constructor
protected Concept(){}
public static class Create<TConcept> where TConcept:Concept
{
//Construct derived Type calling PropertyProxy.ConstructType
public static readonly Type Type = PropertyProxy.ConstructType<TConcept, Implementation<TConcept>>(new Type[0], true);
//Create constructing delegate calling Constructor.Compile
public static Func<TConcept> New = Constructor.Compile<Func<TConcept>>(Type);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
{
var caller = PropertyChanged;
if(caller!=null)
{
caller(this, eventArgs);
}
}
//define implementation
public class Implementation<TConcept> : DefaultImplementation<TConcept> where TConcept:Concept
{
public override Func<TBaseType, TResult> OverrideGetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
{
return PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
}
/// <summary>
/// Overriding property setter implementation.
/// </summary>
/// <typeparam name="TBaseType">Base type for implementation. TBaseType must be TConcept, and inherits all its constraints. Also TBaseType is TDeclaringType.</typeparam>
/// <typeparam name="TDeclaringType">Type, declaring property.</typeparam>
/// <typeparam name="TConstructedType">Constructed type. TConstructedType is TDeclaringType and TBaseType.</typeparam>
/// <typeparam name="TResult">Type of property.</typeparam>
/// <param name="property">PropertyInfo of property.</param>
/// <returns>Delegate, corresponding to property setter implementation.</returns>
public override Action<TBaseType, TResult> OverrideSetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
{
//This code called once for each declared property on derived type's initialization.
//EventArgs instance is shared between all events for each concrete property.
var eventArgs = new PropertyChangedEventArgs(property.Name);
//get delegates for base calls.
Action<TBaseType, TResult> setter = PropertyImplementation<TBaseType, TDeclaringType>.GetSetter<TResult>(property.Name);
Func<TBaseType, TResult> getter = PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
var comparer = EqualityComparer<TResult>.Default;
return (pthis, value) =>
{//This code executes each time property setter is called.
if (comparer.Equals(value, getter(pthis))) return;
//base. call
setter(pthis, value);
//Directly accessing Concept's protected method.
pthis.OnPropertyChanged(eventArgs);
};
}
}
}
It is fully safe for refactoring, uses no reflection after type construction and fast enough.
Whilst there are obviously lots of ways to do this, with the exception of the AOP magic answers, none of the answers seem to look at setting a Model's property directly from the view model without having a local field to reference.
The issue is you can't reference a property. However, you can use an Action to set that property.
protected bool TrySetProperty<T>(Action<T> property, T newValue, T oldValue, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(oldValue, newValue))
{
return false;
}
property(newValue);
RaisePropertyChanged(propertyName);
return true;
}
This can be used like the following code extract.
public int Prop {
get => model.Prop;
set => TrySetProperty(x => model.Prop = x, value, model.Prop);
}
Check out this BitBucket repo for a full implementation of the method and a few different ways of achieving the same result, including a method that uses LINQ and a method that uses reflection. Do note that these methods are slower performance wise.
All these answer are very nice.
My solution is using the code snippets to do the job.
This uses the simplest call to PropertyChanged event.
Save this snippet and use it as you use 'fullprop' snippet.
the location can be found at 'Tools\Code Snippet Manager...' menu at Visual Studio.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>inotifypropfull</Title>
<Shortcut>inotifypropfull</Shortcut>
<HelpUrl>http://ofirzeitoun.wordpress.com/</HelpUrl>
<Description>Code snippet for property and backing field with notification</Description>
<Author>Ofir Zeitoun</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>The variable backing this property</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set {
$field$ = value;
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs("$property$"));
}
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
You can modify the call as you like (to use the above solutions)
Based on the answer by Thomas which was adapted from an answer by Marc I've turned the reflecting property changed code into a base class:
public abstract class PropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
protected void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
var me = selectorExpression.Body as MemberExpression;
// Nullable properties can be nested inside of a convert function
if (me == null)
{
var ue = selectorExpression.Body as UnaryExpression;
if (ue != null)
me = ue.Operand as MemberExpression;
}
if (me == null)
throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(me.Member.Name);
}
protected void SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression, params Expression<Func<object>>[] additonal)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
OnPropertyChanged(selectorExpression);
foreach (var item in additonal)
OnPropertyChanged(item);
}
}
Usage is the same as Thomas' answer except that you can pass additional properties to notify for. This was necessary to handle calculated columns which need to be refreshed in a grid.
private int _quantity;
private int _price;
public int Quantity
{
get { return _quantity; }
set { SetField(ref _quantity, value, () => Quantity, () => Total); }
}
public int Price
{
get { return _price; }
set { SetField(ref _price, value, () => Price, () => Total); }
}
public int Total { get { return _price * _quantity; } }
I have this driving a collection of items stored in a BindingList exposed via a DataGridView. It has eliminated the need for me to do manual Refresh() calls to the grid.
I created an Extension Method in my base Library for reuse:
public static class INotifyPropertyChangedExtensions
{
public static bool SetPropertyAndNotify<T>(this INotifyPropertyChanged sender,
PropertyChangedEventHandler handler, ref T field, T value,
[CallerMemberName] string propertyName = "",
EqualityComparer<T> equalityComparer = null)
{
bool rtn = false;
var eqComp = equalityComparer ?? EqualityComparer<T>.Default;
if (!eqComp.Equals(field,value))
{
field = value;
rtn = true;
if (handler != null)
{
var args = new PropertyChangedEventArgs(propertyName);
handler(sender, args);
}
}
return rtn;
}
}
This works with .Net 4.5 because of CallerMemberNameAttribute.
If you want to use it with an earlier .Net version you have to change the method declaration from: ...,[CallerMemberName] string propertyName = "", ... to ...,string propertyName, ...
Usage:
public class Dog : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _name;
public string Name
{
get { return _name; }
set
{
this.SetPropertyAndNotify(PropertyChanged, ref _name, value);
}
}
}
I keep this around as a snippet. C# 6 adds some nice syntax for invoking the handler.
// INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void Set<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(property, value) == false)
{
property = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have just found ActiveSharp - Automatic INotifyPropertyChanged, I have yet to use it, but it looks good.
To quote from it's web site...
Send property change notifications
without specifying property name as a
string.
Instead, write properties like this:
public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); } // <-- no property name here
}
Note that there is no need to include the name of the property as a string. ActiveSharp reliably and correctly figures that out for itself. It works based on the fact that your property implementation passes the backing field (_foo) by ref. (ActiveSharp uses that "by ref" call to identify which backing field was passed, and from the field it identifies the property).
If you are using dynamics in .NET 4.5 you don't need to worry about INotifyPropertyChanged.
dynamic obj = new ExpandoObject();
obj.Name = "John";
if Name is bound to some control it just works fine.
Another combined solution is using StackFrame:
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T field, T value)
{
MethodBase method = new StackFrame(1).GetMethod();
field = value;
Raise(method.Name.Substring(4));
}
protected void Raise(string propertyName)
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Usage:
public class TempVM : BaseViewModel
{
private int _intP;
public int IntP
{
get { return _intP; }
set { Set<int>(ref _intP, value); }
}
}
I resolved in This Way (it's a little bit laboriouse, but it's surely the faster in runtime).
In VB (sorry, but I think it's not hard translate it in C#), I make this substitution with RE:
(?<Attr><(.*ComponentModel\.)Bindable\(True\)>)( |\r\n)*(?<Def>(Public|Private|Friend|Protected) .*Property )(?<Name>[^ ]*) As (?<Type>.*?)[ |\r\n](?![ |\r\n]*Get)
with:
Private _${Name} As ${Type}\r\n${Attr}\r\n${Def}${Name} As ${Type}\r\nGet\r\nReturn _${Name}\r\nEnd Get\r\nSet (Value As ${Type})\r\nIf _${Name} <> Value Then \r\n_${Name} = Value\r\nRaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs("${Name}"))\r\nEnd If\r\nEnd Set\r\nEnd Property\r\n
This transofrm all code like this:
<Bindable(True)>
Protected Friend Property StartDate As DateTime?
In
Private _StartDate As DateTime?
<Bindable(True)>
Protected Friend Property StartDate As DateTime?
Get
Return _StartDate
End Get
Set(Value As DateTime?)
If _StartDate <> Value Then
_StartDate = Value
RaiseEvent PropertyChange(Me, New ComponentModel.PropertyChangedEventArgs("StartDate"))
End If
End Set
End Property
And If I want to have a more readable code, I can be the opposite just making the following substitution:
Private _(?<Name>.*) As (?<Type>.*)[\r\n ]*(?<Attr><(.*ComponentModel\.)Bindable\(True\)>)[\r\n ]*(?<Def>(Public|Private|Friend|Protected) .*Property )\k<Name> As \k<Type>[\r\n ]*Get[\r\n ]*Return _\k<Name>[\r\n ]*End Get[\r\n ]*Set\(Value As \k<Type>\)[\r\n ]*If _\k<Name> <> Value Then[\r\n ]*_\k<Name> = Value[\r\n ]*RaiseEvent PropertyChanged\(Me, New (.*ComponentModel\.)PropertyChangedEventArgs\("\k<Name>"\)\)[\r\n ]*End If[\r\n ]*End Set[\r\n ]*End Property
With
${Attr} ${Def} ${Name} As ${Type}
I throw to replace the IL code of the set method, but I can't write a lot of compiled code in IL... If a day I write it, I'll say you!
Here is a Unity3D or non-CallerMemberName version of NotifyPropertyChanged
public abstract class Bindable : MonoBehaviour, INotifyPropertyChanged
{
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
private static readonly StackTrace stackTrace = new StackTrace();
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Resolves a Property's name from a Lambda Expression passed in.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="property"></param>
/// <returns></returns>
internal string GetPropertyName<T>(Expression<Func<T>> property)
{
var expression = (MemberExpression) property.Body;
var propertyName = expression.Member.Name;
Debug.AssertFormat(propertyName != null, "Bindable Property shouldn't be null!");
return propertyName;
}
#region Notification Handlers
/// <summary>
/// Notify's all other objects listening that a value has changed for nominated propertyName
/// </summary>
/// <param name="propertyName"></param>
internal void NotifyOfPropertyChange(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Notifies subscribers of the property change.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="property">The property expression.</param>
internal void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property)
{
var propertyName = GetPropertyName(property);
NotifyOfPropertyChange(propertyName);
}
/// <summary>
/// Raises the <see cref="PropertyChanged" /> event directly.
/// </summary>
/// <param name="e">The <see cref="PropertyChangedEventArgs" /> instance containing the event data.</param>
internal void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
#endregion
#region Getters
/// <summary>
/// Gets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
internal T Get<T>(Expression<Func<T>> property)
{
var propertyName = GetPropertyName(property);
return Get<T>(GetPropertyName(property));
}
/// <summary>
/// Gets the value of a property automatically based on its caller.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal T Get<T>()
{
var name = stackTrace.GetFrame(1).GetMethod().Name.Substring(4); // strips the set_ from name;
return Get<T>(name);
}
/// <summary>
/// Gets the name of a property based on a string.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
internal T Get<T>(string name)
{
object value = null;
if (_properties.TryGetValue(name, out value))
return value == null ? default(T) : (T) value;
return default(T);
}
#endregion
#region Setters
/// <summary>
/// Sets the value of a property whilst automatically looking up its caller name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
internal void Set<T>(T value)
{
var propertyName = stackTrace.GetFrame(1).GetMethod().Name.Substring(4); // strips the set_ from name;
Set(value, propertyName);
}
/// <summary>
/// Sets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
internal void Set<T>(T value, string propertyName)
{
Debug.Assert(propertyName != null, "name != null");
if (Equals(value, Get<T>(propertyName)))
return;
_properties[propertyName] = value;
NotifyOfPropertyChange(propertyName);
}
/// <summary>
/// Sets the value of a property based off an Expression (()=>FieldName)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="property"></param>
internal void Set<T>(T value, Expression<Func<T>> property)
{
var propertyName = GetPropertyName(property);
Debug.Assert(propertyName != null, "name != null");
if (Equals(value, Get<T>(propertyName)))
return;
_properties[propertyName] = value;
NotifyOfPropertyChange(propertyName);
}
#endregion
}
This code enables you to write property backing fields like this:
public string Text
{
get { return Get<string>(); }
set { Set(value); }
}
Furthermore, in resharper if you create a pattern/search snippet you can then also automate you're workflow by converting simple prop fields into the above backing.
Search Pattern:
public $type$ $fname$ { get; set; }
Replace Pattern:
public $type$ $fname$
{
get { return Get<$type$>(); }
set { Set(value); }
}
I have written an article that helps with this (https://msdn.microsoft.com/magazine/mt736453). You can use the SolSoft.DataBinding NuGet package. Then you can write code like this:
public class TestViewModel : IRaisePropertyChanged
{
public TestViewModel()
{
this.m_nameProperty = new NotifyProperty<string>(this, nameof(Name), null);
}
private readonly NotifyProperty<string> m_nameProperty;
public string Name
{
get
{
return m_nameProperty.Value;
}
set
{
m_nameProperty.SetValue(value);
}
}
// Plus implement IRaisePropertyChanged (or extend BaseViewModel)
}
Benefits:
base class is optional
no reflection on every 'set value'
can have properties that depend on other properties, and they all automatically raise the appropriate events (article has an example of this)
I came up with this base class to implement the observable pattern, pretty much does what you need ("automatically" implementing the set and get). I spent line an hour on this as prototype, so it doesn't have many unit tests, but proves the concept. Note it uses the Dictionary<string, ObservablePropertyContext> to remove the need for private fields.
public class ObservableByTracking<T> : IObservable<T>
{
private readonly Dictionary<string, ObservablePropertyContext> _expando;
private bool _isDirty;
public ObservableByTracking()
{
_expando = new Dictionary<string, ObservablePropertyContext>();
var properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList();
foreach (var property in properties)
{
var valueContext = new ObservablePropertyContext(property.Name, property.PropertyType)
{
Value = GetDefault(property.PropertyType)
};
_expando[BuildKey(valueContext)] = valueContext;
}
}
protected void SetValue<T>(Expression<Func<T>> expression, T value)
{
var keyContext = GetKeyContext(expression);
var key = BuildKey(keyContext.PropertyName, keyContext.PropertyType);
if (!_expando.ContainsKey(key))
{
throw new Exception($"Object doesn't contain {keyContext.PropertyName} property.");
}
var originalValue = (T)_expando[key].Value;
if (EqualityComparer<T>.Default.Equals(originalValue, value))
{
return;
}
_expando[key].Value = value;
_isDirty = true;
}
protected T GetValue<T>(Expression<Func<T>> expression)
{
var keyContext = GetKeyContext(expression);
var key = BuildKey(keyContext.PropertyName, keyContext.PropertyType);
if (!_expando.ContainsKey(key))
{
throw new Exception($"Object doesn't contain {keyContext.PropertyName} property.");
}
var value = _expando[key].Value;
return (T)value;
}
private KeyContext GetKeyContext<T>(Expression<Func<T>> expression)
{
var castedExpression = expression.Body as MemberExpression;
if (castedExpression == null)
{
throw new Exception($"Invalid expression.");
}
var parameterName = castedExpression.Member.Name;
var propertyInfo = castedExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new Exception($"Invalid expression.");
}
return new KeyContext {PropertyType = propertyInfo.PropertyType, PropertyName = parameterName};
}
private static string BuildKey(ObservablePropertyContext observablePropertyContext)
{
return $"{observablePropertyContext.Type.Name}.{observablePropertyContext.Name}";
}
private static string BuildKey(string parameterName, Type type)
{
return $"{type.Name}.{parameterName}";
}
private static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
public bool IsDirty()
{
return _isDirty;
}
public void SetPristine()
{
_isDirty = false;
}
private class KeyContext
{
public string PropertyName { get; set; }
public Type PropertyType { get; set; }
}
}
public interface IObservable<T>
{
bool IsDirty();
void SetPristine();
}
Here's the usage
public class ObservableByTrackingTestClass : ObservableByTracking<ObservableByTrackingTestClass>
{
public ObservableByTrackingTestClass()
{
StringList = new List<string>();
StringIList = new List<string>();
NestedCollection = new List<ObservableByTrackingTestClass>();
}
public IEnumerable<string> StringList
{
get { return GetValue(() => StringList); }
set { SetValue(() => StringIList, value); }
}
public IList<string> StringIList
{
get { return GetValue(() => StringIList); }
set { SetValue(() => StringIList, value); }
}
public int IntProperty
{
get { return GetValue(() => IntProperty); }
set { SetValue(() => IntProperty, value); }
}
public ObservableByTrackingTestClass NestedChild
{
get { return GetValue(() => NestedChild); }
set { SetValue(() => NestedChild, value); }
}
public IList<ObservableByTrackingTestClass> NestedCollection
{
get { return GetValue(() => NestedCollection); }
set { SetValue(() => NestedCollection, value); }
}
public string StringProperty
{
get { return GetValue(() => StringProperty); }
set { SetValue(() => StringProperty, value); }
}
}
Other things you may want to consider when implementing these sorts of properties is the fact that the INotifyPropertyChang *ed *ing both use event argument classes.
If you have a large number of properties that are being set then the number of event argument class instances can be huge, you should consider caching them as they are one of the areas that a string explosion can occur.
Take a look at this implementation and explanation of why it was conceived.
Josh Smiths Blog
An idea using reflection:
class ViewModelBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
bool Notify<T>(MethodBase mb, ref T oldValue, T newValue) {
// Get Name of Property
string name = mb.Name.Substring(4);
// Detect Change
bool changed = EqualityComparer<T>.Default.Equals(oldValue, newValue);
// Return if no change
if (!changed) return false;
// Update value
oldValue = newValue;
// Raise Event
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(name));
}//if
// Notify caller of change
return true;
}//method
string name;
public string Name {
get { return name; }
set {
Notify(MethodInfo.GetCurrentMethod(), ref this.name, value);
}
}//method
}//class
Use this
using System;
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
public static class ObservableFactory
{
public static T Create<T>(T target)
{
if (!typeof(T).IsInterface)
throw new ArgumentException("Target should be an interface", "target");
var proxy = new Observable<T>(target);
return (T)proxy.GetTransparentProxy();
}
}
internal class Observable<T> : RealProxy, INotifyPropertyChanged, INotifyPropertyChanging
{
private readonly T target;
internal Observable(T target)
: base(ImplementINotify(typeof(T)))
{
this.target = target;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
if (methodCall != null)
{
return HandleMethodCall(methodCall);
}
return null;
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
IMessage HandleMethodCall(IMethodCallMessage methodCall)
{
var isPropertySetterCall = methodCall.MethodName.StartsWith("set_");
var propertyName = isPropertySetterCall ? methodCall.MethodName.Substring(4) : null;
if (isPropertySetterCall)
{
OnPropertyChanging(propertyName);
}
try
{
object methodCalltarget = target;
if (methodCall.MethodName == "add_PropertyChanged" || methodCall.MethodName == "remove_PropertyChanged"||
methodCall.MethodName == "add_PropertyChanging" || methodCall.MethodName == "remove_PropertyChanging")
{
methodCalltarget = this;
}
var result = methodCall.MethodBase.Invoke(methodCalltarget, methodCall.InArgs);
if (isPropertySetterCall)
{
OnPropertyChanged(methodCall.MethodName.Substring(4));
}
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (TargetInvocationException invocationException)
{
var exception = invocationException.InnerException;
return new ReturnMessage(exception, methodCall);
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanging(string propertyName)
{
var handler = PropertyChanging;
if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));
}
public static Type ImplementINotify(Type objectType)
{
var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());
var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
tempAssemblyName, AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = dynamicAssembly.DefineDynamicModule(
tempAssemblyName.Name,
tempAssemblyName + ".dll");
var typeBuilder = moduleBuilder.DefineType(
objectType.FullName, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
typeBuilder.AddInterfaceImplementation(objectType);
typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanging));
var newType = typeBuilder.CreateType();
return newType;
}
}
}
I use the following extension method (using C# 6.0) to make the INPC implemenation as easy as possible:
public static bool ChangeProperty<T>(this PropertyChangedEventHandler propertyChanged, ref T field, T value, object sender,
IEqualityComparer<T> comparer = null, [CallerMemberName] string propertyName = null)
{
if (comparer == null)
comparer = EqualityComparer<T>.Default;
if (comparer.Equals(field, value))
{
return false;
}
else
{
field = value;
propertyChanged?.Invoke(sender, new PropertyChangedEventArgs(propertyName));
return true;
}
}
The INPC implementation boils down to (you can either implement this every time or create a base class):
public class INPCBaseClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool changeProperty<T>(ref T field, T value,
IEqualityComparer<T> comparer = null, [CallerMemberName] string propertyName = null)
{
return PropertyChanged.ChangeProperty(ref field, value, this, comparer, propertyName);
}
}
Then write your properties like this:
private string testProperty;
public string TestProperty
{
get { return testProperty; }
set { changeProperty(ref testProperty, value); }
}
NOTE: You can omit the [CallerMemberName] declaration in the extension method, if you want, but I wanted to keep it flexible.
If you have properties without a backing field you can overload changeProperty:
protected bool changeProperty<T>(T property, Action<T> set, T value,
IEqualityComparer<T> comparer = null, [CallerMemberName] string propertyName = null)
{
bool ret = changeProperty(ref property, value, comparer, propertyName);
if (ret)
set(property);
return ret;
}
An example use would be:
public string MyTestProperty
{
get { return base.TestProperty; }
set { changeProperty(base.TestProperty, (x) => { base.TestProperty = x; }, value); }
}
I realize this question already has a gazillion answers, but none of them felt quite right for me. My issue is I don't want any performance hits and am willing to put up with a little verbosity for that reason alone. I also don't care too much for auto properties either, which led me to the following solution:
public abstract class AbstractObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual bool SetValue<TKind>(ref TKind Source, TKind NewValue, params string[] Notify)
{
//Set value if the new value is different from the old
if (!Source.Equals(NewValue))
{
Source = NewValue;
//Notify all applicable properties
foreach (var i in Notify)
OnPropertyChanged(i);
return true;
}
return false;
}
public AbstractObject()
{
}
}
In other words, the above solution is convenient if you don't mind doing this:
public class SomeObject : AbstractObject
{
public string AnotherProperty
{
get
{
return someProperty ? "Car" : "Plane";
}
}
bool someProperty = false;
public bool SomeProperty
{
get
{
return someProperty;
}
set
{
SetValue(ref someProperty, value, "SomeProperty", "AnotherProperty");
}
}
public SomeObject() : base()
{
}
}
Pros
No reflection
Only notifies if old value != new value
Notify multiple properties at once
Cons
No auto properties (you can add support for both, though!)
Some verbosity
Boxing (small performance hit?)
Alas, it is still better than doing this,
set
{
if (!someProperty.Equals(value))
{
someProperty = value;
OnPropertyChanged("SomeProperty");
OnPropertyChanged("AnotherProperty");
}
}
For every single property, which becomes a nightmare with the additional verbosity ;-(
Note, I do not claim this solution is better performance-wise compared to the others, just that it is a viable solution for those who don't like the other solutions presented.
I suggest to use ReactiveProperty.
This is the shortest method except Fody.
public class Data : INotifyPropertyChanged
{
// boiler-plate
...
// props
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}
}
instead
public class Data
{
// Don't need boiler-plate and INotifyPropertyChanged
// props
public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>();
}
(DOCS)

Is there syntactic sugar to shorten the OnPropertyChanged construct? [duplicate]

Is there any way to automatically get notified of property changes in a class without having to write OnPropertyChanged in every setter? (I have hundreds of properties that I want to know if they have changed).
Anton suggests dynamic proxies. I've actually used the "Castle" library for something similar in the past, and while it does reduce the amount of code I've had to write, it added around 30 seconds to my program startup time (ymmv) - because it's a runtime solution.
I'm wondering if there is a compile time solution, maybe using compile-time attributes...
Slashene and TcKs give suggestions which generates repetitive code - unfortunately, not all my properties are a simple case of m_Value = value - lots of them have custom code in the setters, so cookie-cutter code from snippets and xml aren't really feasible for my project either.
EDIT: The author of NotifyPropertyWeaver has deprecated the tool in favor of the more general Fody. (A migration guide for people moving from weaver to fody is available.)
A very convenient tool I've used for my projects is Notify Property Weaver Fody.
It installs itself as a build step in your projects and during compilation injects code that raises the PropertyChanged event.
Making properties raise PropertyChanged is done by putting special attributes on them:
[ImplementPropertyChanged]
public string MyProperty { get; set; }
As a bonus, you can also specify relationships for properties that depend on other properties
[ImplementPropertyChanged]
public double Radius { get; set; }
[DependsOn("Radius")]
public double Area
{
get { return Radius * Radius * Math.PI; }
}
The nameof operator was implemented in C# 6.0 with .NET 4.6 and VS2015 in July 2015. The following is still valid for C# < 6.0
We use the code below (From http://www.ingebrigtsen.info/post/2008/12/11/INotifyPropertyChanged-revisited.aspx). Works great :)
public static class NotificationExtensions
{
#region Delegates
/// <summary>
/// A property changed handler without the property name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sender">The object that raised the event.</param>
public delegate void PropertyChangedHandler<TSender>(TSender sender);
#endregion
/// <summary>
/// Notifies listeners about a change.
/// </summary>
/// <param name="EventHandler">The event to raise.</param>
/// <param name="Property">The property that changed.</param>
public static void Notify(this PropertyChangedEventHandler EventHandler, Expression<Func<object>> Property)
{
// Check for null
if (EventHandler == null)
return;
// Get property name
var lambda = Property as LambdaExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
ConstantExpression constantExpression;
if (memberExpression.Expression is UnaryExpression)
{
var unaryExpression = memberExpression.Expression as UnaryExpression;
constantExpression = unaryExpression.Operand as ConstantExpression;
}
else
{
constantExpression = memberExpression.Expression as ConstantExpression;
}
var propertyInfo = memberExpression.Member as PropertyInfo;
// Invoke event
foreach (Delegate del in EventHandler.GetInvocationList())
{
del.DynamicInvoke(new[]
{
constantExpression.Value, new PropertyChangedEventArgs(propertyInfo.Name)
});
}
}
/// <summary>
/// Subscribe to changes in an object implementing INotifiyPropertyChanged.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ObjectThatNotifies">The object you are interested in.</param>
/// <param name="Property">The property you are interested in.</param>
/// <param name="Handler">The delegate that will handle the event.</param>
public static void SubscribeToChange<T>(this T ObjectThatNotifies, Expression<Func<object>> Property, PropertyChangedHandler<T> Handler) where T : INotifyPropertyChanged
{
// Add a new PropertyChangedEventHandler
ObjectThatNotifies.PropertyChanged += (s, e) =>
{
// Get name of Property
var lambda = Property as LambdaExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
var propertyInfo = memberExpression.Member as PropertyInfo;
// Notify handler if PropertyName is the one we were interested in
if (e.PropertyName.Equals(propertyInfo.Name))
{
Handler(ObjectThatNotifies);
}
};
}
}
Used for example this way:
public class Employee : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _firstName;
public string FirstName
{
get { return this._firstName; }
set
{
this._firstName = value;
this.PropertyChanged.Notify(()=>this.FirstName);
}
}
}
private void firstName_PropertyChanged(Employee sender)
{
Console.WriteLine(sender.FirstName);
}
employee = new Employee();
employee.SubscribeToChange(() => employee.FirstName, firstName_PropertyChanged);
Some syntax errors in the example may exist. Didn't test it. But you should have the concept there at least :)
EDIT: I see now that you may have wanted even less work, but yeah... the stuff above at least makes it a lot easier. And you prevent all the scary problems with refering to properties using strings.
The Framework 4.5 provides us with the CallerMemberNameAttribute, which makes passing the property name as a string unnecessary:
private string m_myProperty;
public string MyProperty
{
get { return m_myProperty; }
set
{
m_myProperty = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "none passed")
{
// ... do stuff here ...
}
Similar to Svish's solution, just replacing lambda awesomeness with boring framework functionality ;-)
If you're working on Framework 4.0 with KB2468871 installed, you can install the Microsoft BCL Compatibility Pack via nuget, which also provides this attribute.
You can have extension method on your PropertyChanged delegate and use it like this:
public string Name
{
get { return name; }
set
{
name = value;
PropertyChanged.Raise(() => Name);
}
}
Subscription to a specific property change:
var obj = new Employee();
var handler = obj.SubscribeToPropertyChanged(
o => o.FirstName,
o => Console.WriteLine("FirstName is now '{0}'", o.FirstName));
obj.FirstName = "abc";
// Unsubscribe when required
obj.PropertyChanged -= handler;
extension method is able to determine sender and property name just by inspecting lambda expression tree and without major performance impact:
public static class PropertyChangedExtensions
{
public static void Raise<TProperty>(
this PropertyChangedEventHandler handler, Expression<Func<TProperty>> property)
{
if (handler == null)
return;
var memberExpr = (MemberExpression)property.Body;
var propertyName = memberExpr.Member.Name;
var sender = ((ConstantExpression)memberExpr.Expression).Value;
handler.Invoke(sender, new PropertyChangedEventArgs(propertyName));
}
public static PropertyChangedEventHandler SubscribeToPropertyChanged<T, TProperty>(
this T obj, Expression<Func<T, TProperty>> property, Action<T> handler)
where T : INotifyPropertyChanged
{
if (handler == null)
return null;
var memberExpr = (MemberExpression)property.Body;
var propertyName = memberExpr.Member.Name;
PropertyChangedEventHandler subscription = (sender, eventArgs) =>
{
if (propertyName == eventArgs.PropertyName)
handler(obj);
};
obj.PropertyChanged += subscription;
return subscription;
}
}
If PropertyChanged event is declared in a base type then it won't be visible as a delegate field in the derived classes. In this case a workaround is to declare a protected field of type PropertyChangedEventHandler and explicitly implement event's add and remove accessors:
public class Base : INotifyPropertyChanged
{
protected PropertyChangedEventHandler propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
add { propertyChanged += value; }
remove { propertyChanged -= value; }
}
}
public class Derived : Base
{
string name;
public string Name
{
get { return name; }
set
{
name = value;
propertyChanged.Raise(() => Name);
}
}
}
Implement a type safe INotifyPropertyChanged : See here
Then make your own code snippet :
private $Type$ _$PropertyName$;
public $Type$ $PropertyName$
{
get
{
return _$PropertyName$;
}
set
{
if(value != _$PropertyName$)
{
_$PropertyName$ = value;
OnPropertyChanged(o => o.$PropertyName$);
}
}
}
With Code snippet designer and you have done ! Easy, secure way to build your INotifyPropertyChanged.
I don't know no standard way, but I know two workarounds:
1) PostSharp can do it for you after the compilation. It is very usefull, but it take some time on every build.
2) Custom tool i Visual Studio. You can combine it with "partial class". Then you can create custom tool for your XML and you can generate source code from the xml.
For example this xml:
<type scope="public" type="class" name="MyClass">
<property scope="public" type="string" modifier="virtual" name="Text" notify="true" />
</type>
can be source for this code:
public partial class MyClass {
private string _text;
public virtual string Text {
get { return this._Text; }
set {
this.OnPropertyChanging( "Text" );
this._Text = value;
this.OnPropertyChanged( "Text" );
}
}
}
you might want to look into Aspect-Oriented Programming as a whole
Frameworks => you could look at linfu
You could look at Castle or Spring.NET and implementing interceptor functionality?
I have just found ActiveSharp - Automatic INotifyPropertyChanged, I have yet to use it, but it looks good.
To quote from it's web site...
Send property change notifications
without specifying property name as a
string.
Instead, write properties like this:
public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); } // <-- no property name here
}
Note that there is no need to include the name of the property as a string. ActiveSharp reliably and correctly figures that out for itself. It works based on the fact that your property implementation passes the backing field (_foo) by ref. (ActiveSharp uses that "by ref" call to identify which backing field was passed, and from the field it identifies the property).
Amelioration to call event in children classes:
Called thanks to:
this.NotifyPropertyChange(() => PageIndex);
Add this in the NotificationExtensions class:
/// <summary>
/// <para>Lève l'évènement de changement de valeur sur l'objet <paramref name="sender"/>
/// pour la propriété utilisée dans la lambda <paramref name="property"/>.</para>
/// </summary>
/// <param name="sender">L'objet portant la propriété et l'évènement.</param>
/// <param name="property">Une expression lambda utilisant la propriété subissant la modification.</param>
public static void NotifyPropertyChange(this INotifyPropertyChanged sender, Expression<Func<Object>> property)
{
if (sender == null)
return;
// Récupère le nom de la propriété utilisée dans la lambda en argument
LambdaExpression lambda = property as LambdaExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
UnaryExpression unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
ConstantExpression constantExpression = memberExpression.Expression as ConstantExpression;
PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
// il faut remonter la hierarchie, car meme public, un event n est pas visible dans les enfants
FieldInfo eventField;
Type baseType = sender.GetType();
do
{
eventField = baseType.GetField(INotifyPropertyChangedEventFieldName, BindingFlags.Instance | BindingFlags.NonPublic);
baseType = baseType.BaseType;
} while (eventField == null);
// on a trouvé l'event, on peut invoquer tt les delegates liés
MulticastDelegate eventDelegate = eventField.GetValue(sender) as MulticastDelegate;
if (eventDelegate == null) return; // l'event n'est bindé à aucun delegate
foreach (Delegate handler in eventDelegate.GetInvocationList())
{
handler.Method.Invoke(handler.Target, new Object[] { sender, new PropertyChangedEventArgs(propertyInfo.Name) });
}
}
Just to make the implementation quicker you can use a snippet
From http://aaron-hoffman.blogspot.it/2010/09/visual-studio-code-snippet-for-notify.html
the ViewModel classes of projects following the M-V-VM pattern it is often necessary to raise a "PropertyChanged" event (to assist with INotifyPropertyChanged interface implementation) from within a property's setter. This is a tedious task that will hopefully someday be solved by using the Compiler as a Service...
Snippet core (for which full credit goes to the author, who is not me) is the following
<Code Language= "csharp ">
<![CDATA[public $type$ $property$
{
get { return _$property$; }
set
{
if (_$property$ != value)
{
_$property$ = value;
OnPropertyChanged($property$PropertyName);
}
}
}
private $type$ _$property$;
public const string $property$PropertyName = "$property$";$end$]]>
</Code>
There is no Single implementation of Property Changed that can handle every way that people want to use it. best bet is to generate a helper class to do the work for you
here is an example of one i use
/// <summary>
/// Helper Class that automates most of the actions required to implement INotifyPropertyChanged
/// </summary>
public static class HPropertyChanged
{
private static Dictionary<string, PropertyChangedEventArgs> argslookup = new Dictionary<string, PropertyChangedEventArgs>();
public static string ThisPropertyName([CallerMemberName]string name = "")
{
return name;
}
public static string GetPropertyName<T>(Expression<Func<T>> exp)
{
string rtn = "";
MemberExpression mex = exp.Body as MemberExpression;
if(mex!=null)
rtn = mex.Member.Name;
return rtn;
}
public static void SetValue<T>(ref T target, T newVal, object sender, PropertyChangedEventHandler handler, params string[] changed)
{
if (!target.Equals(newVal))
{
target = newVal;
PropertyChanged(sender, handler, changed);
}
}
public static void SetValue<T>(ref T target, T newVal, Action<PropertyChangedEventArgs> handler, params string[] changed)
{
if (!target.Equals(newVal))
{
target = newVal;
foreach (var item in changed)
{
handler(GetArg(item));
}
}
}
public static void PropertyChanged(object sender,PropertyChangedEventHandler handler,params string[] changed)
{
if (handler!=null)
{
foreach (var prop in changed)
{
handler(sender, GetArg(prop));
}
}
}
public static PropertyChangedEventArgs GetArg(string name)
{
if (!argslookup.ContainsKey(name)) argslookup.Add(name, new PropertyChangedEventArgs(name));
return argslookup[name];
}
}
edit:
it was suggested that i shift from a helper class to a value wrapper and i've since been using this one and i find it works quite well
public class NotifyValue<T>
{
public static implicit operator T(NotifyValue<T> item)
{
return item.Value;
}
public NotifyValue(object parent, T value = default(T), PropertyChangingEventHandler changing = null, PropertyChangedEventHandler changed = null, params object[] dependenies)
{
_parent = parent;
_propertyChanged = changed;
_propertyChanging = changing;
if (_propertyChanged != null)
{
_propertyChangedArg =
dependenies.OfType<PropertyChangedEventArgs>()
.Union(
from d in dependenies.OfType<string>()
select new PropertyChangedEventArgs(d)
);
}
if (_propertyChanging != null)
{
_propertyChangingArg =
dependenies.OfType<PropertyChangingEventArgs>()
.Union(
from d in dependenies.OfType<string>()
select new PropertyChangingEventArgs(d)
);
}
_PostChangeActions = dependenies.OfType<Action>();
}
private T _Value;
public T Value
{
get { return _Value; }
set
{
SetValue(value);
}
}
public bool SetValue(T value)
{
if (!EqualityComparer<T>.Default.Equals(_Value, value))
{
OnPropertyChnaging();
_Value = value;
OnPropertyChnaged();
foreach (var action in _PostChangeActions)
{
action();
}
return true;
}
else
return false;
}
private void OnPropertyChnaged()
{
var handler = _propertyChanged;
if (handler != null)
{
foreach (var arg in _propertyChangedArg)
{
handler(_parent, arg);
}
}
}
private void OnPropertyChnaging()
{
var handler = _propertyChanging;
if(handler!=null)
{
foreach (var arg in _propertyChangingArg)
{
handler(_parent, arg);
}
}
}
private object _parent;
private PropertyChangedEventHandler _propertyChanged;
private PropertyChangingEventHandler _propertyChanging;
private IEnumerable<PropertyChangedEventArgs> _propertyChangedArg;
private IEnumerable<PropertyChangingEventArgs> _propertyChangingArg;
private IEnumerable<Action> _PostChangeActions;
}
example of use
private NotifyValue<int> _val;
public const string ValueProperty = "Value";
public int Value
{
get { return _val.Value; }
set { _val.Value = value; }
}
then in constructor you do
_val = new NotifyValue<int>(this,0,PropertyChanged,PropertyChanging,ValueProperty );
Just Use this attribute above your automatic property declaration
[NotifyParentProperty(true)]
public object YourProperty { get; set; }

Pass Property and get class

This might be a trivial question but I am drawing a blank here and can't seem to find the answer online.
Basically, I am trying to create a method that takes 2 properties that are part of an INotifyPropertyChanged class as parameters (the actual properties to be used in reflection, not the property values), and keep them "in sync" like a binding.
Example
I have a class called Student with a property called int SemesterScore. I have another class called Semester with a property called int Score. Both of the classes implement IPropertyNotifyChanged.
Now, let's just assume for a moment that we can't extend any of the classes (as in my real-life scenario) and I may have multiple times in different classes I want to use this.
Basically, I want to be able to call a method in one of my classes that "links" the two properties together.. aka if one of them changes it will auto-update the other.
In non-working code, this is the basic concept:
public class Student : INotifyPropertyChanged
{
private int _semesterScore;
public int SemeseterScore
{
get { return _semesterScore; }
set { [ set property stuff with property changed] }
}
}
public class Semester: INotifyPropertyChanged
{
private int _score;
public int Score
{
get { return _score; }
set { [ set property stuff with property changed] }
}
}
public class Entry
{
public static void Main(string[] args)
{
Student student = new Student();
Semester semester = new Semester();
AttachProperties(student.SemesterScore, semester.Score); // This obviously won't work, but this is where I pass the properties in
semester.Score = 7;
Console.WriteLine(student.SemesterScore); // Output will be 7
}
public static void AttachProperties([sometype] prop1, [sometype] prop2)
{
// Sudo code
prop1.classInstance.PropertyChanged += (pe)
{
if (pe.Property == prop1.Name)
prop2.Value = prop1.Value;
}
prop2.classInstance.PropertyChanged += (pe)
{
if (pe.Property == prop2.Name)
prop1.Value = prop2.Value;
}
}
}
Is there any way to do this? I know some workarounds (aka pass the INotifyPropertyChanged classes and the property names, then do some reflection to get that to work), but the question of passing property instances around (and doing stuff with it) has come up a few times in my coding career.
One way to do this would be to use an Observable, like #itay-podhacer suggested above.
But if you want to implement using just Reflection and INotifyPropertyChanged here is how you could do it.
First, lets get SemesterScore and Student both implement INotifyPropertyChanged:
public class Student : INotifyPropertyChanged
{
private int semesterScore;
public int SemesterScore
{
get { return semesterScore; }
set
{
semesterScore = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Semester : INotifyPropertyChanged
{
private int score;
public int Score
{
get { return score; }
set
{
score = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now lets tie the properties together, in your AttachProperties helper method. In order to do this, we will make the AttachProperties method take Expression<Func<T,object> arguments so that we avoid passing magic strings and can use Reflection to retrieve the properties names.
By the way, to run this in production you probably want to memoize that reflection code for performance.
private static void AttachProperties<T1,T2>(Expression<Func<T1, object>> property1, T1 instance1, Expression<Func<T2, object>> property2, T2 instance2)
where T1 : INotifyPropertyChanged
where T2 : INotifyPropertyChanged
{
var p1 = property1.GetPropertyInfo();
var p2 = property2.GetPropertyInfo();
//A NULL or empty PropertyName in PropertyChangeEventArgs means that all properties changed
//See: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged(v=vs.110).aspx#Anchor_1
((INotifyPropertyChanged)instance1).PropertyChanged += (_, e) =>
{
if (e.PropertyName == p1.Name || string.IsNullOrEmpty(e.PropertyName))
{
SyncProperties(p1, p2, instance1, instance2);
}
};
((INotifyPropertyChanged)instance2).PropertyChanged += (_, e) =>
{
if (e.PropertyName == p2.Name || string.IsNullOrEmpty(e.PropertyName))
{
SyncProperties(p2, p1, instance2, instance1);
}
};
}
private static void SyncProperties(PropertyInfo sourceProperty, PropertyInfo targetProperty, object sourceInstance, object targetInstance)
{
var sourceValue = sourceProperty.GetValue(sourceInstance);
var targetValue = targetProperty.GetValue(targetInstance);
if (!sourceValue.Equals(targetValue))
{
targetProperty.SetValue(targetInstance, sourceValue);
}
}
And, finally, here is the Reflection code to retrieve the PropertyInfo from the arguments:
public static class ReflectionExtension
{
public static PropertyInfo GetPropertyInfo<T>(this Expression<Func<T, object>> expression)
{
var memberExpression = GetMemberExpression(expression);
return (PropertyInfo)memberExpression.Member;
}
private static MemberExpression GetMemberExpression<TModel, T>(Expression<Func<TModel, T>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)expression.Body;
memberExpression = body.Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "expression");
}
return memberExpression;
}
}
With all this in place, you can keep two properties in sync now:
public class PropertySyncTests
{
public void Should_sync_properties()
{
var semester = new Semester();
var student = new Student();
AttachProperties(x => x.Score, semester, x => x.SemesterScore, student);
semester.Score = 7;
student.SemesterScore.ShouldBe(7);
}
}
I know some workarounds (aka pass the INotifyPropertyChanged classes and the property names, then do some reflection to get that to work), but the question of passing property instances around (and doing stuff with it) has come up a few times in my coding career.
This is, ultimately, the way to do it. However, I think one key trick that you might not be aware of is Expression Trees. It is possible to create a function that takes an Expression<Func<T>> as an argument, and then delve into the Expression Tree to discover the INotifyPropertyChanged instance and the property that's given in the argument. Usage could look like this:
AttachProperties(() => student.SemesterScore, () => semester.Score);
The arguments to AttachProperties in the example above would be Expressions with the following structure.
<LambdaExpression> () => student.SemesterScore
Body <MemberExpression> student.SemesterScore
Member <PropertyInfo> SemesterScore
Expression <MemberExpression> student
Member <FieldInfo> [closure class.]student
Expression <ConstantExpression> [closure]
Value [closure instance]
Notice that you're creating a closure by using student inside of the lambda expression, so to get the value of student you'll need to use reflection to get the value of the [closure class].student field. Getting the SemesterScore property is just a matter of casting the expressions correctly and getting the .Body.Member property from the passed-in lambda expression.
Subscribe to the PropertyChanged event of the semester:
Student student = new Student();
Semester semester = new Semester();
semester.PropertyChanged += Semester_PropertyChanged;
Then assign the new score to the student
private void Semester_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
student.SemesterScore = semester.Score;
}
This will trigger the student's PropertyChanged event and also update his SemesterScore if the score changed.
Take a look at Reactive UI Extensions, it will give you the ability to "observe" a property for changes and then update (or do whatever you want) once such change occurs.
It will allow you to do something like this:
student
.WhenAnyValue(item => item.SemeseterScore)
.Subscribe(item =>
{
semester.Score = item.SemeseterScore
});
semester
.WhenAnyValue(item => item.Score)
.Subscribe(item =>
{
item.SemeseterScore = semester.Score
});
You might need to add an Ignore flag at your class and turn it on and off inside the Subscribe code, so you don't create an endless loop of updates between the two classes.
Ok so I combined #StriplingWarrior and #Pedro's answers together to get my final result:
public static void AttachProperties<T1, T2>(Expression<Func<T1>> property1, Expression<Func<T2>> property2)
{
var instance1 = Expression.Lambda<Func<object>>(((MemberExpression)property1.Body).Expression).Compile()();
var iNotify1 = instance1 as INotifyPropertyChanged;
var prop1 = GetPropertyInfo(property1);
var instance2 = Expression.Lambda<Func<object>>(((MemberExpression)property2.Body).Expression).Compile()();
var iNotify2 = instance2 as INotifyPropertyChanged;
var prop2 = GetPropertyInfo(property2);
AttachProperty(prop1, iNotify1, prop2, iNotify2);
AttachProperty(prop2, iNotify2, prop1, iNotify1);
}
static void AttachProperty(
PropertyInfo property1,
INotifyPropertyChanged class1Instance,
PropertyInfo property2,
INotifyPropertyChanged class2Instance)
{
class2Instance.PropertyChanged += (_, propArgs) =>
{
if (propArgs.PropertyName == property2.Name || string.IsNullOrEmpty(propArgs.PropertyName))
{
var prop = property2.GetValue(class2Instance);
property1.SetValue(class1Instance, prop);
}
};
}
static PropertyInfo GetPropertyInfo<T1>(Expression<Func<T1>> property)
{
MemberExpression expression = null;
if (property.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)property.Body;
expression = body.Operand as MemberExpression;
}
else if (property.Body.NodeType == ExpressionType.MemberAccess)
{
expression = property.Body as MemberExpression;
}
if (expression == null)
{
throw new ArgumentException("Not a member access", nameof(property));
}
return expression.Member as PropertyInfo;
}
This works correctly both in the example I gave and in my real-life project. Thanks!

WPF mvvm property in viewmodel without setter?

I'm dealing with some WPF problems using and sticking to the MVVM pattern.
Most of my properties look like this:
public string Period
{
get { return _primaryModel.Period; }
set
{
if (_primaryModel.Period != value)
{
_primaryModel.Period = value;
RaisePropertyChanged("Period");
}
}
}
This works excellent.
However I also have some properties like this:
public bool EnableConsignor
{
get
{
return (ConsignorViewModel.Id != 0);
}
}
It doesn't have a setter as the id is changed "automatically" (every time the save of ConsignorViewModel is called. However this leads to the problem that the "system" doesn't know when the bool changes from false to true (as no RaisePropertyChanged is called).
For these kinds of properties, you need to just raise PropertyChanged when the dependent data is changed. Something like:
public object ConsignorViewModel
{
get { return consignorViewModel; }
set
{
consignorViewModel = value;
RaisePropertyChanged("ConsignorViewModel");
RaisePropertyChanged("EnableConsignor");
}
}
RaisePropertyChanged can be invoked in any method, so just put it after whatever operation that would change the return value of EnableConsignor is performed. The above was just an example.
I wrote this a while ago an it has been working great
[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public class CalculatedProperty : Attribute
{
private string[] _props;
public CalculatedProperty(params string[] props)
{
this._props = props;
}
public string[] Properties
{
get
{
return _props;
}
}
}
The ViewModel base
public class ObservableObject : INotifyPropertyChanged
{
private static Dictionary<string, Dictionary<string, string[]>> calculatedPropertiesOfTypes = new Dictionary<string, Dictionary<string, string[]>>();
private readonly bool hasComputedProperties;
public ObservableObject()
{
Type t = GetType();
if (!calculatedPropertiesOfTypes.ContainsKey(t.FullName))
{
var props = t.GetProperties();
foreach (var pInfo in props)
{
var attr = pInfo.GetCustomAttribute<CalculatedProperty>(false);
if (attr == null)
continue;
if (!calculatedPropertiesOfTypes.ContainsKey(t.FullName))
{
calculatedPropertiesOfTypes[t.FullName] = new Dictionary<string, string[]>();
}
calculatedPropertiesOfTypes[t.FullName][pInfo.Name] = attr.Properties;
}
}
if (calculatedPropertiesOfTypes.ContainsKey(t.FullName))
hasComputedProperties = true;
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
if (this.hasComputedProperties)
{
//check for any computed properties that depend on this property
var computedPropNames =
calculatedPropertiesOfTypes[this.GetType().FullName]
.Where(kvp => kvp.Value.Contains(propertyName))
.Select(kvp => kvp.Key);
if (computedPropNames != null)
if (!computedPropNames.Any())
return;
//raise property changed for every computed property that is dependant on the property we did just set
foreach (var computedPropName in computedPropNames)
{
//to avoid stackoverflow as a result of infinite recursion if a property depends on itself!
if (computedPropName == propertyName)
throw new InvalidOperationException("A property can't depend on itself");
OnPropertyChanged(computedPropName);
}
}
}
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;
}
}
Example:
public class ViewModel : ObservableObject
{
private int _x;
public int X
{
get { return _x; }
set { SetField(ref _x, value); }
}
private int _y;
public int Y
{
get { return _y; }
set { SetField(ref _y, value); }
}
//use the CalculatedProperty annotation for properties that depend on other properties and pass it the prop names that it depends on
[CalculatedProperty("X", "Y")]
public int Z
{
get { return X * Y; }
}
[CalculatedProperty("Z")]
public int M
{
get { return Y * Z; }
}
}
Note that:
it uses reflection only once per type
SetField sets the field and raises property changed if there is a new value
you don't need to pass property name to SetField as long as you call it within a setter because the
[CallerMemberName] does it for you since c# 5.0.
if you call SetField outside the setter then you will have to pass
it the property name
as per my last update you can avoid using SetField by setting the field directly and then
calling OnPropertyChanged("PropertyName") and it will raise
PropertyChanged for all properties that are
dependant on it.
in c# 6 you can use the nameof operator to get the property name such
as nameof(Property)
OnPropertyChanged will call itself recusively if there are computed
properties
XAML for testing
<StackPanel>
<TextBox Text="{Binding X,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
<TextBox Text="{Binding Y,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
<TextBlock Text="{Binding Z,Mode=OneWay}"></TextBlock>
<TextBlock Text="{Binding M,Mode=OneWay}"></TextBlock>
</StackPanel>

NotifyOnPropertyChange realization

How can I implement NotifyOnPropertyChange method? To call it from the inheritors ViewModelBase could be as:
NotifyOnPropertyChange (() => Property)
The input to this method is applied lambda expression that specifies a property of change which need to notify.
You can implement it like this so you don't have to give the property name at all (as long as it's called directly from the property setter). This way, there is no fear of renaming properties or typos.
private void NotifyOnPropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
Then, implement your property like so:
string _somePropertyValue;
string SomeProperty
{
get { return _somePropertyValue; }
set
{
if(_somePropertyValue != value)
{
_somePropertyValue = value;
NotifyOnPropertyChanged();
}
}
}
Your implementation can look like this. It's implemented using System.Linq.Expressions namespace.
protected void RaisePropertyChanged<T>(System.Linq.Expressions.Expression<Func<T>> lambda)
{
dynamic l = lambda.Body;
string propertyName = l.Member.Name;
OnPropertyChanged(propertyName);
}
Here's an example of the whole class.
public class NotificationObject : INotifyPropertyChanged
{
private string _someProperty;
public string SomeProperty
{
get { return _someProperty; }
set
{
_country = value;
RaisePropertyChanged(() => SomeProperty);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected void RaisePropertyChanged<T>(System.Linq.Expressions.Expression<Func<T>> lambda)
{
dynamic l = lambda.Body;
string propertyName = l.Member.Name;
OnPropertyChanged(propertyName);
}
}
The full blown implementation without using dynamic would look like this:
protected void RaisePropertyChanged<T>(System.Linq.Expressions.Expression<Func<T>> lambda)
{
if (lambda == null) throw new ArgumentNullException("lambda");
var memberExpression = lambda.Body as MemberExpression;
if (memberExpression == null) throw new ArgumentException("Invalid lambda expression.","lambda");
var property = memberExpression.Member as PropertyInfo;
if (property == null) throw new ArgumentException("Invalid lambda expression. Expression must be a property.", "lambda");
// check if the property is not static
var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic) throw new ArgumentException("Invalid lambda expression. Property cannot be static.", "propertyExpression");
string propertyName = memberExpression.Member.Name;
OnPropertyChanged(propertyName);
}
You can use NotificationObject from Prism library. It's already implemented there as RaisePropertyChanged<T>
Here're links to the source code for the NotificationObject and for the PropertySupport classes.

Categories