Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
NotifyPropertyChangedProxy Generic
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
namespace DynamicUtils
{
public class NotifyPropertyChangedProxy<T> : DynamicObject, INotifyPropertyChanged
where T : class
{
public T WrappedObject { get; private set; }
private readonly Dictionary<string, PropertyInfo> _cache = new Dictionary<string, PropertyInfo>();
private bool _allCached;
public NotifyPropertyChangedProxy(T wrappedObject)
{
if (wrappedObject == null)
throw new ArgumentNullException("wrappedObject");
WrappedObject = wrappedObject;
}
#region INotifyPropertyChanged support
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public override IEnumerable<string> GetDynamicMemberNames()
{
if (!_allCached)
{
var properties = WrappedObject.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties.Where(property => !_cache.ContainsKey(property.Name)))
{
_cache[property.Name] = property;
}
}
_allCached = true;
return _cache.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Locate property by name
PropertyInfo propertyInfo;
if (!_cache.TryGetValue(binder.Name, out propertyInfo))
{
propertyInfo = WrappedObject.GetType().GetProperty(binder.Name, BindingFlags.Instance | BindingFlags.Public | (binder.IgnoreCase ? BindingFlags.IgnoreCase : 0));
}
if (propertyInfo == null || !propertyInfo.CanRead)
{
result = null;
return false;
}
result = propertyInfo.GetValue(WrappedObject, null);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Locate property by name
PropertyInfo propertyInfo;
if (!_cache.TryGetValue(binder.Name, out propertyInfo))
{
propertyInfo = WrappedObject.GetType().GetProperty(binder.Name, BindingFlags.Instance | BindingFlags.Public | (binder.IgnoreCase ? BindingFlags.IgnoreCase : 0));
}
if (propertyInfo == null || !propertyInfo.CanWrite)
return false;
object newValue = value;
// Check the types are compatible
Type propertyType = propertyInfo.PropertyType;
if (!propertyType.IsAssignableFrom(value.GetType()))
{
newValue = Convert.ChangeType(value, propertyType);
}
propertyInfo.SetValue(WrappedObject, newValue, null);
OnPropertyChanged(binder.Name);
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment