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.
I found this class in the System.Dynamic
namespace... It lets you intercept the actual DataBinding
calls made by the DependencyObject
on your binding target, to the Property
on your binding source.
So what one could do now is to implement a class (lets call it DynamicNpcProxy
) that implements INotifyPropertyChanged
, is derived from DynamicObject
and overrides both the TryGetMember
and TrySetMember
methods.
public class DynamicNpcProxy : DynamicObject, INotifyPropertyChanged
{
public DynamicNpcProxy(object proxiedObject)
{
ProxiedObject = proxiedObject;
}
//...
public object ProxiedObject { get; set; }
public override bool TrySetMember(SetMemberBinder binder, object value)
{
SetMember(binder.Name, value);
return true;
}
protected virtual void SetMember(string propertyName, object value)
{
GetPropertyInfo(propertyName).SetValue(ProxiedObject, value, null);
if (PropertyChanged != null)
PropertyChanged(ProxiedObject, new PropertyChangedEventArgs(propertyName));
}
protected PropertyInfo GetPropertyInfo(string propertyName)
{
return ProxiedObject.GetType().GetProperty(propertyName);
}
// override bool TryGetMember(...)
}
To get it to work, wrap the proxy around your current binding source, replace them and let DynamicObject
do the rest.
In ViewModel.cs:
IList<ProductWorkItem> items;
//... assign items
var proxies = items.Select(p => new DynamicNpcProxy(p)).ToList();
ICollectionView Products = CollectionViewSource.GetDefaultView(proxies);
In View.xaml:
<TextBox Text="{Binding Products.CurrentItem.Name}" />
<TextBox Text="{Binding Products.CurrentItem.Description}" />
What you end up with is this:
Also check out this article over at the code project
which provides even more information...