I want to get rid of the space consuming and repetitive RaisePropertyChanged-Properties on my model classes. I want my model class...
public class ProductWorkItem : NotificationObject
{
private string name;
public string Name
{
get { return name; }
set {
if (value == name) return;
name = value; RaisePropertyChanged(() => Name);
}
}
private string description;
public string Description
{
get { return description; }
set {
if (value == description) return;
description = value; RaisePropertyChanged(() => Description);
}
}
private string brand;
public string Brand
{
get { return brand; }
set {
if (value == brand) return;
brand = value; RaisePropertyChanged(() => Brand);
}
}
}
...to look as simple as this again: (but notify the view when a property changes)
public class ProductWorkItem
{
public string Name{ get; set; }
public string Description{ get; set; }
public string Brand{ get; set; }
}
Could this be achieved with some sort of proxy class?
I want to avoid writing a proxy for every single model class.
Coming from the other side (and if you don't have a fancy Extension) you can "autospecify" changed properties with the extension methods outlined in my answer here: WCF service proxy not setting "FieldSpecified" property
Specifically, you could use the 'non-reflection method' to configure specific "OnPropertyChanged" handling per class to do other things than just set a specified field.
And then each class themselves defines the behavior:
The downside to this is, of course, magic strings for property names making refactoring difficult, which you could get around with
Expression
parsing?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.
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:
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
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 overridesOnSetValue
method to call yourRaisePropertyChanged
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
This is already an old stuff, just nobody mentioned:
https://kindofmagic.codeplex.com/
You can turn on the automatic notification for every properties in your ViewModel with 1 attribute on the class.
I found this class in the
System.Dynamic
namespace... It lets you intercept the actualDataBinding
calls made by theDependencyObject
on your binding target, to theProperty
on your binding source.http://i.msdn.microsoft.com/en-us/library/system.windows.data.binding.DataBindingMostBasic(v=vs.110).png?appId=Dev11IDEF1&l=EN-US&k=k(System.Windows.Data.Binding)%3bk(VS.XamlEditor)%3bk(TargetFrameworkMoniker-.NETFramework
So what one could do now is to implement a class (lets call it
DynamicNpcProxy
) that implementsINotifyPropertyChanged
, is derived fromDynamicObject
and overrides both theTryGetMember
andTrySetMember
methods.To get it to work, wrap the proxy around your current binding source, replace them and let
DynamicObject
do the rest.In ViewModel.cs:
In View.xaml:
What you end up with is this:
Also check out this article over at the
code project
which provides even more information...