Avoid calling RaisePropertyChanged in every setter
I know of no simple and maintainable approach to this in "vanilla" C#, but you can achieve this with aspects. I have used PostSharp for this, which has a disadvantage of being a paid 3rd party product, but has a free version, where you can do this as well. PostSharp leverages the advantages of attributes like target specifying, inheritance etc. and extends them to aspects.
You can then define a LocationInterceptionAspect
, which overrides OnSetValue
method to call your RaisePropertyChanged
delegate. Then you can use autogenerated properties decorated with your aspect attribute.
Paid version of PostSharp allows you to do this on class level, so you would only need one attribute (or none, if you decorate your base class and define the attribute as inheritable). This is described on the PostSharp site as a use case of InstanceLevelAspect
I came along the NotifyPropertyWeaver extension and haved used it on a regular basis since then. It's a Visual Studio extension, which implements the always same INPC stuff for you, before the code gets compiled. You don't notice anything of that.
You need to install the extension, and your model then needs to look like this:
public class ProductWorkItem : INotifyPropertyChanged
{
public string Name{ get; set; }
public string Description{ get; set; }
public string Brand{ get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
The extension than adds all the rest for you. What I like about that approach, is that your class still "officially" implements the INPC interface and you can use it in non-WPF contexts as well (as INPC is not at all just a WPF thing), but still don't have to litter you classes with all that stuff. It raises notifications for readonly properties that depend on a property.
Of course, it's a bit fake, as it just automizes the writing and doesn't change anything about the underlying concept at all. But maybe it's a compromise...
Here is more information: Link
We can avoid repetitive code of writing RaisePropertyChanged on each property setter in WPF.
Use free version of Postsharp.
By using following code we can bind only Virtual property to view.
namespace Test
{
[Serializable]
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)]
public sealed class RaisePropertyChangedAttribute : MethodInterceptionAspect
{
private string propertyName;
/// <summary>
/// Compiles the time validate.
/// </summary>
/// <param name="method">The method.</param>
public override bool CompileTimeValidate(MethodBase method)
{
return IsPropertySetter(method) && !method.IsAbstract && IsVirtualProperty(method);
}
/// <summary>
/// Method invoked at build time to initialize the instance fields of the current aspect. This method is invoked
/// before any other build-time method.
/// </summary>
/// <param name="method">Method to which the current aspect is applied</param>
/// <param name="aspectInfo">Reserved for future usage.</param>
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
base.CompileTimeInitialize(method, aspectInfo);
propertyName = GetPropertyName(method);
}
/// <summary>
/// Determines whether [is virtual property] [the specified method].
/// </summary>
/// <param name="method">The method.</param>
/// <returns>
/// <c>true</c> if [is virtual property] [the specified method]; otherwise, <c>false</c>.
/// </returns>
private static bool IsVirtualProperty(MethodBase method)
{
if (method.IsVirtual)
{
return true;
}
var getMethodName = method.Name.Replace("set_", "get_");
var getMethod = method.DeclaringType.GetMethod(getMethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return getMethod != null && getMethod.IsVirtual;
}
private static string GetPropertyName(MethodBase method)
{
return method.Name.Replace("set_", string.Empty);
}
/// <summary>
/// Determines whether [is property setter] [the specified method].
/// </summary>
/// <param name="method">The method.</param>
/// <returns>
/// <c>true</c> if [is property setter] [the specified method]; otherwise, <c>false</c>.
/// </returns>
private static bool IsPropertySetter(MethodBase method)
{
return method.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Method invoked <i>instead</i> of the method to which the aspect has been applied.
/// </summary>
/// <param name="args">Advice arguments.</param>
public override void OnInvoke(MethodInterceptionArgs args)
{
var arg = args as MethodInterceptionArgsImpl;
if ((arg != null) && (arg.TypedBinding == null))
{
return;
}
// Note ViewModelBase is base class for ViewModel
var target = args.Instance as ViewModelBase;
args.Proceed();
if (target != null)
{
target.OnPropertyChanged(propertyName);
}
}
}
}