I'm having a very curious problem in which I have tests failing with:
System.InvalidCastException: Unable to cast object of type
'<>c__DisplayClass18_0' to type
'System.ComponentModel.INotifyPropertyChanged'.
However, when I run "debug test", tests are green, wether I run the debug from unit tests or live tests 'debug'. Therefore it's tricky to investigate. Furthermore I never had any problem using those ICommand implementation in the app.
I should not have any Exception (I don't have any in unit tests, I have in live tests and VS doesn't reach (break) the exception in this case, even though it's happening). How should I go forward ?
The cast problem happens at ListenForNotificationFrom((INotifyPropertyChanged) _executeDelegate.Target); in the class DelegateCommandListen.
EDIT: Wether the Action<T> is a private named function (1) or a local function (2) or a lambda (2), its property Target is well defined, and should be casted to INotifyPropertyChanged. Where (1) works for both live tests and unit tests, and (2) works only in unit tests.
My ICommand implementation:
public class DelegateCommandListen : ICommand
{
private readonly List<WeakReference> _controlEvent;
private Action<object> _executeDelegate;
public DelegateCommandListen(Action<object> executeDelegate, Predicate<object> canExecuteDelegate)
{
_controlEvent = new List<WeakReference>();
ExecuteDelegate = executeDelegate;
CanExecuteDelegate = canExecuteDelegate;
}
public Predicate<object> CanExecuteDelegate { get; set; }
public Action<object> ExecuteDelegate
{
get { return _executeDelegate; }
set
{
_executeDelegate = value;
ListenForNotificationFrom((INotifyPropertyChanged) _executeDelegate.Target);
}
}
public void RaiseCanExecuteChanged()
{
if (_controlEvent != null && _controlEvent.Count > 0)
_controlEvent.ForEach(ce => { ((EventHandler) ce.Target)?.Invoke(null, EventArgs.Empty); });
}
public DelegateCommandListen ListenOn<TObservedType, TPropertyType>
(TObservedType viewModel, Expression<Func<TObservedType, TPropertyType>> propertyExpression)
where TObservedType : INotifyPropertyChanged
{
var propertyName = GetPropertyName(propertyExpression);
viewModel.PropertyChanged += (s, e) =>
{
if (e.PropertyName == propertyName) RaiseCanExecuteChanged();
};
return this;
}
public void ListenForNotificationFrom<TObservedType>(TObservedType viewModel)
where TObservedType : INotifyPropertyChanged
{
viewModel.PropertyChanged += (s, e) => RaiseCanExecuteChanged();
}
private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> expression)
where T : INotifyPropertyChanged
{
var lambda = expression as LambdaExpression;
var memberInfo = GetMemberExpression(lambda).Member;
return memberInfo.Name;
}
private static MemberExpression GetMemberExpression(LambdaExpression lambda)
{
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression body)
{
var unaryExpression = body;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
memberExpression = lambda.Body as MemberExpression;
return memberExpression;
}
public bool CanExecute(object parameter) => CanExecuteDelegate == null || CanExecuteDelegate(parameter);
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
_controlEvent.Add(new WeakReference(value));
}
remove
{
CommandManager.RequerySuggested -= value;
_controlEvent.Remove(_controlEvent.Find(r => (EventHandler) r.Target == value));
}
}
public void Execute(object parameter) => ExecuteDelegate?.Invoke(parameter);
}
Here is how I test the viewmodel:
[TestMethod]
public void NoTarget()
{
var sut = new DummyViewModel();
Assert.IsFalse(sut.IsSelected);
Assert.IsFalse(sut.ListenWithoutTargetCommand.CanExecute(null));
sut.IsSelected = true;
Assert.IsTrue(sut.ListenWithoutTargetCommand.CanExecute(null));
}
The ViewModel:
public class DummyViewModel : INotifyPropertyChanged
{
private ICommand _listenWith1TargetCommand;
private bool _isSelected;
public string Result { get; set; }
public bool IsSelected
{
get => _isSelected;
set
{
if (value == _isSelected) return;
_isSelected = value;
OnPropertyChanged();
}
}
public ICommand ListenWith1TargetCommand
{
get
{
return _listenWith1TargetCommand ?? (_listenWith1TargetCommand = new DelegateCommandListen(
s => { Result = "Executing listen command 1"; }, // lambda|local function|named function
s => IsSelected)
.ListenOn(this, o => o.IsSelected));
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Full sources: https://github.com/mprevot/ReproLiveTests
According to Artur Spychaj (MSFT), tests fail because LUT (Live Unit Testing) modifies the lambdas to capture the coverage information and the compiler moves the lambda around into a separate class. The workaround is to pass this as a separate parameter of DelegateCommandListen.
We mortals usually do not get to see Roslyn bugs :) So it is important to try to solve the problem at hand by investigating rather than blaming the tools :)
I think Visual Studio is telling you the exact problem.
System.InvalidCastException: Unable to cast object of type '<>c__DisplayClass18_0' to type 'System.ComponentModel.INotifyPropertyChanged'.
Moreover, you almost solved the problem yourself. You mention that anonymous lambda is not working but named functions are working.
Let us work out your problem one by one. First of all what is the Action<T>.Target property. Just copy and paste from Visual Studio.
The object on which the current delegate invokes the instance method,
if the delegate represents an instance method; null if the delegate
represents a static method.
So what do you think happens when you pass an anonymous lambda? How do we pass anonymous lambda in the first place? Well, you may already know, so I will just refresh everyone's memory. Compiler in the background creates a class, in your case <>c__DisplayClass18_0 and sets the anonymous lambda as properties of the said generated class and passes it along as if they are named functions of a proper class! This is important.
What is going on in your case then? When you pass an anonymous lambda
ListenForNotificationFrom((INotifyPropertyChanged) _executeDelegate.Target);
_executeDelegate's.Target is a compiler generated class '<>c__DisplayClass18_0', which does not implement, of course, System.ComponentModel.INotifyPropertyChanged. This is what is going on. It is not a Roslyn bug, in fact it is exactly how it is supposed to be :)
Edit: Just adding a Debug screenshot. It is in Japanese but I guess you can clearly see that it is the same as OP's message.
Related
I have a question regarding the following code:
public class MyClass : INotifyPropertyChanged
{
private bool _myProp;
public bool MyProp
{
get { return _myProp; }
set
{
_myProp = value;
RaisePropertyChanged(() => MyProp);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
This may not be the best way to identify a property name, but I have used it before, even in the same project; however, the above code won't compile. There's several workarounds for this; some of which may be better solutions that what is above, however, I'd still like to find out why this doesn't work.
The specific compile error I get is:
error CS1660: Cannot convert lambda expression to type 'string' because it is not a delegate type
Checkout the new CallerMemberName attribute. I only found out about it via mvvm light but will never do notify property changed the old way again.
http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute(v=vs.110).aspx
You need a method that accepts Expression<Func<T>>, extracts the property name as a string, and then raises the PropertyChanged event with it. It won't be done automatically. I usually make it an extension method, to save implementing the same code over and over or having it in a base class:
public static class RaisePropertyChangedExtensions
{
public static void RaisePropertyChanged<T>(
this IRaisePropertyChanged raisePropertyChangedImpl,
Expression<Func<T>> expr)
{
var memberExprBody = expr.Body as MemberExpression;
string property = memberExprBody.Member.Name;
raisePropertyChangedImpl.RaisePropertyChanged(property);
}
}
Your view-models just need to implement the IRaisePropertyChanged interface:
public interface IRaisePropertyChanged : INotifyPropertyChanged
{
void RaisePropertyChanged(string property);
}
..and the usage is exactly the same as in your question:
this.RaisePropertyChanged(() => MyProp);
Of course, you can always make this a method on your view-model - just remove the generic parameter and pass your view-model type to the function.
You need to use expressions:
public static string GetPropertyName<T, TPropValue>(this Expression<Func<T, TPropValue>> propertySelector) where T : class
{
Condition.Requires(propertySelector, "propertySelector").IsNotNull();
var memberExpr = propertySelector.Body as MemberExpression;
if (memberExpr == null)
throw new ArgumentException("Provider selector is not property selector.");
var propInfo = memberExpr.Member as PropertyInfo;
if (propInfo == null)
throw new NotSupportedException("You can properties only.");
return propInfo.Name;
}
protected void RaisePropertyChanged(Expression<Func<MyClass, string>> propSelector)
{
if (PropertyChanged != null)
{
var propertyName = propertySelecotr.GetPropertyName();
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Usage:
RaisePropertyChanged(myClass => myClass.MyProp);
Solved
I've been looking for a while and I can't find the solution. Maybe because I'm not so fluent with expressions.
What I want to do, is to raise a property change in Class2 from the Class1. I can do this when I communicate the string of the property to update. What I want is to use expressions to avoid typos.
The prototype below works perfectly well when I'm using strings to define the parameter to update in the class2.
I use the event aggregator to propagate the property to update.
I have a Class1 looking like this:
public class Class1
{
public string Name
{
get { return _name; }
set
{
_name = value;
RaiseClass2PropertyChanged(() => Name);
}
}
private void RaiseClass2PropertyChanged(Expression<Func<Class2>> expression)
{
ServiceLocator.EventAggregator
.GetEvent<UpdateClass2Property>().Publish(expression);
}
}
In the class2, I have:
public class Class2
{
public Class2 (IEventAggregator evt)
{
evt.GetEvent<UpdateClass2Property>()
.Subscribe(x => RaisePropertyChanged(() => x));
}
public string Name
{
get { return SomeFunction(); }
}
}
And the event:
internal class UpdateClass2Property :
CompositePresentationEvent<Expression<Func<Class2>>> { }
When I use RaiseClass2PropertyChanged(() => Name);, I have an error at compilation time:
Cannot implicitly convert type 'string' to 'Class2'
EDIT: (solved)
I manage to solve the compilation error by doing this
private void RaiseClass2PropertyChanged(Expression<Func<Class2, string>> expression)
{
ServiceLocator.EventAggregator.GetEvent<UpdateClass2Property>().Publish(expression);
}
So now I can do this in my Class1
public string Property1
{
get { return _property1; }
set { _property1 = value;
RaiseClass2PropertyChanged(x => x.Class2Property);
}
}
But now I have to solve the problem in the Class2 to retrieve the property name.
I managed to solve this by doing this in my Class2:
public Class2(IEventAggregator evt)
{
evt.GetEvent<UpdateClass2Property>().Subscribe(Method);
}
private void Method(Expression<Func<Class2, string>> expression)
{
var memberExpr = expression.Body as MemberExpression;
if (memberExpr == null)
throw new ArgumentException("propertyExpression should represent access to a member");
string memberName = memberExpr.Member.Name;
RaisePropertyChanged(memberName);
}
Of course, I changed the signature of UpdateSnapshotProperty
internal class UpdateSnapshotProperty : CompositePresentationEvent<Expression<Func<SnapshotViewModel, string>>> { }
Thanks for your help
For property change you need to pass on string but your expression is expecting instance of Class2.
Change
private void RaiseClass2PropertyChanged(Expression<Func<Class2>> expression)
to
private void RaiseClass2PropertyChanged(Expression<Func<string>> expression)
Also
internal class UpdateClass2Property :
CompositePresentationEvent<Expression<Func<Class2>>> { }
should be
internal class UpdateClass2Property :
CompositePresentationEvent<Expression<Func<string>>> { }
I am setting up a WPF application with a ViewModel that has lots of properties. These are all very repetitive and I am wondering if there is a way to get rid of this. This is what one property looks like, and I have about 8-10 of them.
public string Name
{
get
{
return this.name;
}
set
{
if (this.name != value)
{
this.name = value;
this.RaisePropertyChanged("Name");
}
}
}
My suggestion, if your requirements are straightforward, would be to go third party. This is a solved problem, thanks to some ingenious people...
The most bare-bones way you can write your code is to remove the INotifyPropertyChanged implementation entirely, and write your properties in the minimal way like this:
public string Name { get; set; }
Then add Fody.PropertyChanged to your project (it's on NuGet) and mark your class with the [ImplementPropertyChanged] attribute.
Fody will do some clever IL magic during compilation that will implement the interface and all of the boilerplate code magically - meaning your written code is as simple as can be, and your end result is exactly what you want.
Note that if you rely on the INotifyPropertyChanged interface elsewhere in your code (that is, if you manually attach to the event in code or similar), you may want to use Fody differently because the IDE won't realise you've got the interface implemented. Fortunately, Fody will also auto-implement in other scenarios too (e.g.: implement INotifyPropertyChanged in a class and Fody will, by default also implement event raising in your properties).
The mentioned thread contains indeed the answer but you need to do some digging. I will show the two best answers I found in there.
The first solution is to implement a ViewModelBase class that encapsulates the set method into a template method and uses lamda expressions to retrieve the Property name so refactoring does not break the property name string.
public class ViewModelBase: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
var 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;
}
}
Usage:
class ViewModel : DataBase
{
private String _prop1;
public String Prop1
{
get { return _prop1; }
set
{
SetField(ref _prop1, value, () => Prop1);
}
}
}
The second solution uses a Dictionary to store the properties in the base class. This way we do not need to pass in the old value as it is kept in the base class and we do not need to create member fields to hold the values for the properties. I like this solution the best:
public abstract class ViewModelBase : INotifyPropertyChanged
{
private readonly Dictionary<string, object> _propertyValueStorage;
#region Constructor
protected ViewModelBase()
{
this._propertyValueStorage = new Dictionary<string, object>();
}
#endregion
protected void SetValue<T>(Expression<Func<T>> property, T value)
{
var lambdaExpression = property as LambdaExpression;
if (lambdaExpression == null)
{
throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
}
var propertyName = this.getPropertyName(lambdaExpression);
var storedValue = this.getValue<T>(propertyName);
if (object.Equals(storedValue, value)) return;
this._propertyValueStorage[propertyName] = value;
this.OnPropertyChanged(propertyName);
}
protected T GetValue<T>(Expression<Func<T>> property)
{
var lambdaExpression = property as LambdaExpression;
if (lambdaExpression == null)
{
throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
}
var propertyName = this.getPropertyName(lambdaExpression);
return getValue<T>(propertyName);
}
private T getValue<T>(string propertyName)
{
object value;
if (_propertyValueStorage.TryGetValue(propertyName, out value))
{
return (T)value;
}
return default(T);
}
private string getPropertyName(LambdaExpression lambdaExpression)
{
MemberExpression memberExpression;
if (lambdaExpression.Body is UnaryExpression)
{
var unaryExpression = lambdaExpression.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambdaExpression.Body as MemberExpression;
}
return memberExpression.Member.Name;
}
#region < INotifyPropertyChanged > Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Usage would be:
public class ViewModel : ViewModelBase
{
public String Prop1
{
get { return GetValue(() => Prop1); }
set { SetValue(() => Prop1, value); }
}
public bool Bool1
{
get { return GetValue(() => Bool1); }
set { SetValue(() => Bool1, value); }
}
Solution 1 is based on https://stackoverflow.com/a/1316566/2259878 and https://stackoverflow.com/a/1316566/2259878
Solution 2 is based on http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
It depends on the requirement, if all the properties are used for same purpose means like name1, name2, name3.....name10, like listing names of 10 people, then put in a another class and bind a collection of the class type to Items-control in your xaml. or simply bind a ObservableCollection of string
But if each of properties has its own purpose then it can not avoid, because Properties are nothing but variables to hold different values. Each property will have it's own intention and operation on each of them will vary in the view model, depending on logic
My solution is near to uncletall's but with some changes for usage
private static readonly Properties<MainWindowViewModel> _properties = new Properties<MainWindowViewModel>();
public static Property TextProperty = _properties.Create(_ => _.Text);
private string _text;
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value, TextProperty); }
}
XAML:
<Label Grid.Row="1" Content="{Model:PropertyBinding {x:Static Model:MainWindowViewModel.TextProperty}}" Width="200"/>
Benefit of this sample is compile-time check for changes.
Full sample link
So far my model implements INotifyPropertyChanged, and every property raises this event.
Almost all ViewModels listen to these changes via the PropertyChangedEventHandler.
The problem is that this handler gets called for every change in the model, even if the property change is not important for the View.
One option is to check which property raised the event. However, I don not like the idea to test the PropertyName string. It requires the hard coding of the property name which I already avoided in the Model with calls like PropertyChanged.Notify(()=> PropertyName)
The second option I see is to implement for all my properties single event:
public event PropertyChangedEventHandler LayerChanged;
public event PropertyChangedEventHandler FieldChanged;
public event PropertyChangedEventHandler LinkDictionaryChanged;
....
What is the best practice? I would prefer the second option.
EDIT: I try to be more specific
My Model classes work like that:
public bool IsFeatureLayer
{
get { return _isFeatureLayer; }
set { PropertyChanged.ChangeAndNotify(ref _isFeatureLayer, value, () => IsFeatureLayer);}
}
Or
PropertyChanged.Notify(() => LinkDictionary);
So the question is not how to make the notification call safer, because I already use extension methods to do this without the string name of the property.
The question is how to find out who invoked the event without using a string.
void _MCDAExtensionPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName.Equals("LinkDictionary"){
//event handling
}
}
This is totally unsafe because the name of the Property in my model can change and I have to fix it on different places.
If you're targeting .NET 4.5, implementing INotifyPropertyChanged is a lot easier and safer with the new CallerMemberName attribute.
In short, the CallerMemberName attribute allows you to get the name of the calling member as a method parameter. This way, you can have something like this:
private string name;
public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string callerMemberName = "")
{
// callerMemberName = "Name" (the property that called it).
// Set the field value and raise PropertyChanged event.
}
You can see an example of how to use it here.
As for which option to choose - I believe that the difference in terms of execution time is negligible, as opposed to the coding overhead and code clutter (both in the code itself and with intellisense) you get for having an extra event for each property. I would definitely go with the first option.
EDIT:
Unfortunately, when handling the PropertyChanged event, you can only test against the PropertyName string, and there is no way to get that string in a way that remains consistent even when the property name changes. For dependency properties you have MyDependencyProperty.Name, but that's not applicable for regular properties.
Eventually, your options are either to use a different event for each property, or define a constant in the class defining the property that holds the property name, hoping that you'll remember to modify it when/if you change the property name. Assuming you don't have many classes that implement INotifyPropertyChanged where you attach a handler yourself, having an event for each property in those specific classes isn't that bad.
If I understand your question correctly, you could use something like this:
public static class PropertyChangedExtensions
{
public static void RegisterPropertyHandler<T, TProperty>(this T obj, Expression<Func<T, TProperty>> propertyExpression, PropertyChangedEventHandler handlerDelegate)
where T : class, INotifyPropertyChanged
{
if (obj == null) throw new ArgumentNullException("obj");
var propertyName = GetPropertyName(propertyExpression);
obj.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == propertyName && handlerDelegate != null)
handlerDelegate(sender, args);
};
}
public static void Notify<T>(this PropertyChangedEventHandler eventHandler, object sender, Expression<Func<T>> propertyExpression)
{
var handler = eventHandler;
if (handler != null) handler(sender, new PropertyChangedEventArgs(GetPropertyName(propertyExpression)));
}
private static string GetPropertyName(LambdaExpression propertyExpression)
{
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
var unaryExpression = propertyExpression.Body as UnaryExpression;
if (unaryExpression == null)
throw new ArgumentException("Expression must be a UnaryExpression.", "propertyExpression");
memberExpression = unaryExpression.Operand as MemberExpression;
}
if (memberExpression == null)
throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("Expression must be a Property.", "propertyExpression");
return propertyInfo.Name;
}
}
The RegisterPropertyHandler method allows you to register a handler for a specific property without using "magic strings". You use it like this:
public class PersonViewModel : INotifyPropertyChanged
{
public PersonViewModel()
{
Address = new AddressViewModel();
Address.RegisterPropertyHandler(a => a.ZipCode, ZipCodeChanged);
}
private AddressViewModel _address;
public AddressViewModel Address
{
get { return _address; }
set
{
_address = value;
PropertyChanged.Notify(this, () => Address);
}
}
private static void ZipCodeChanged(object sender, PropertyChangedEventArgs args)
{
// This will only be called when the 'ZipCode' property of 'Address' changes.
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class AddressViewModel : INotifyPropertyChanged
{
private string _zipCode;
public string ZipCode
{
get
{
return _zipCode;
}
set
{
_zipCode = value;
PropertyChanged.Notify(this, () => ZipCode);
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I see you already have a Notify extension method, so you would only need to add the RegisterPropertyHandler. At least this is a start :)
Just to your project extension method like this:
public static string GetPropertyName<TObj,TRet>(this TObj obj, Expression<Func<TObj,TRet>> expression)
{
MemberExpression body = GetMemberExpression(expression);
return body.Member.Name;
}
This way you will have compile checking of Properties names, string with property name in expense of little performance. With this you can call:
PropertyChanged.Notify(this.GetPropetyName(t=>t.PropertyName))
It's not ideal but without strings it's hard to accomplish that.
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; }