Skip to content

Instantly share code, notes, and snippets.

@caleb-vear
Created April 7, 2011 02:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caleb-vear/906916 to your computer and use it in GitHub Desktop.
Save caleb-vear/906916 to your computer and use it in GitHub Desktop.
Sample code for a blog post I wrote about: WPF Bindings Not Updating When PropertyChanged Raised When Bound Against a Proxy Object
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="YourAppName">
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.connection_string">
Server=(local);initial catalog=nhibernate;Integrated Security=SSPI
</property>
<property name="proxyfactory.factory_class"> YouProjectNameSpace.FixDataBindingProxyFactoryFactory, YourProjectAssembly</property>
</session-factory>
</hibernate-configuration>
public class ShoppingCart : INotifyPropertyChanged
{
public virtual Guid Id { get; private set; }
public virtual IList<CartItem> _items = new ObservableCollection<CartItem>();
public virtual IEnumerable<CartItem> { get { return _items; } }
public virtual decimal Total { get { return _items.Sum(i => i.Price); } }
public virtual void AddItem(CartItem item)
{
_items.Add(item);
// We raise this event to notify subscribers that our Total has very likely changed its value.
PropertyChanged(this, new PropertyChangedEventArgs("Total"));
}
public virtual event PropertyChangedEventHandler PropertyChanged = delegate {};
}
public class FixDataBindingLazyInitializer : LazyInitializer
{
private PropertyChangedEventHandler _subscribers = delegate { };
public object ProxyInstance { get; set; }
public FixDataBindingInterceptor(String entityName, Type persistentClass, object id, MethodInfo getIdentifierMethod, MethodInfo setIdentifierMethod, IAbstractComponentType aType, ISessionImplementor session)
: base(entityName, persistentClass, id, getIdentifierMethod, setIdentifierMethod, aType, session)
{
}
public override void Intercept(Castle.DynamicProxy.IInvocation invocation)
{
// WPF will call a method named add_PropertyChanged to subscribe itself to the property changed events of
// the given entity. The method to call is stored in invocation.Arguments[0]. We get this and add it to the
// proxy subscriber list.
if (invocation.Method.Name.EndsWith("PropertyChanged"))
{
PropertyChangedEventHandler propertyChangedEventHandler = (PropertyChangedEventHandler)invocation.Arguments[0];
if (invocation.Method.Name.StartsWith("add_"))
{
_subscribers += propertyChangedEventHandler;
}
else
{
_subscribers -= propertyChangedEventHandler;
}
}
else
{
base.Intercept(invocation);
}
}
public override void Initialize()
{
base.Initialize();
var notifyPropertyChanged = Target as INotifyPropertyChanged;
if (notifyPropertyChanged != null)
{
// We subscribe to our Target's property changed event so we can pass it on
// to any objects that subscribe to the proxies event.
notifyPropertyChanged.PropertyChanged += TargetPropertyChanged;
}
}
void TargetPropertyChanged(object sender, PropertyChangedEventArgs e)
{
_subscribers(ProxyInstance, e);
}
}
public class FixDataBindingProxyFactory : ProxyFactory
{
public override INHibernateProxy GetProxy(object id, ISessionImplementor session)
{
// If it is not a proxy for a class do what you usually did.
if (!IsClassProxy) return base.GetProxy(id, session);
try
{
var initializer = new FixDataBindingLazyInitializer(EntityName, PersistentClass, id,
GetIdentifierMethod, SetIdentifierMethod, ComponentIdType, session);
// Add to the list of the interfaces that the proxy class will support the INotifyPropertyChanged interface.
// This is only needed in the case when we need to cast our proxy object as INotifyPropertyChanged interface.
var extraInterfaces = new[] {typeof (INotifyPropertyChanged)};
var interfaces = Interfaces.Concat(extraInterfaces).ToArray();
object generatedProxy = DefaultProxyGenerator.CreateClassProxy(PersistentClass, interfaces, initializer);
initializer._constructed = true;
initializer.ProxyInstance = generatedProxy;
return (INHibernateProxy)generatedProxy;
}
catch (Exception e)
{
log.Error("Creating a proxy instance failed", e);
throw new HibernateException("Creating a proxy instance failed", e);
}
}
}
public class FixDataBindingProxyFactoryFactory : IProxyFactoryFactory
{
public IProxyFactory BuildProxyFactory()
{
return new FixDataBindingProxyFactory();
}
public bool IsInstrumented(Type entityClass)
{
return true;
}
public IProxyValidator ProxyValidator
{
get { return new DynProxyTypeValidator(); }
}
}
@Martin-Andersen
Copy link

Can you please update the code to use the new build in proxy in NH >= 3.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment