Windsor Castle Proxies, Implicit Interfaces, and WPF Binding

I am trying to implement WPM ViewModel using Dynamic Proxies Castle Windsor. The idea is that I want to provide an interface (for example, IPerson below as an example), a specific support class, and an interceptor (to ensure the automatic implementation of INotifyPropertyChanged). The interceptor implementation is here: http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever

The problem I see is that when I bind my models to WPF controls, the controls do not see the models as an implementation of INotifyPropertyChanged. I believe (but not sure) that this is because Windsor explicitly implements the interfaces, and WPF seems to expect them to be implicit.

Is there a way to make this work so that changes to the model are captured by the interceptor and pulled up to the model?

All versions of the libraries are the latest: Castle.Core 2.5.1.0 and Windsor 2.5.1.0

The code is as follows:

// My model interface
public interface IPerson : INotifyPropertyChanged
{
    string First { get; set; }
    string LastName { get; set; }
    DateTime Birthdate { get; set; }
}

// My concrete class:
[Interceptor(typeof(NotifyPropertyChangedInterceptor))]
class Person : IPerson
{
    public event PropertyChangedEventHandler PropertyChanged = (s,e)=> { };
    public string First { get; set; }
    public string LastName { get; set; }
    public DateTime Birthdate { get; set; }
}

// My windsor installer
public class Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<NotifyPropertyChangedInterceptor>()
            .ImplementedBy<NotifyPropertyChangedInterceptor>()
            .LifeStyle.Transient);
        container.Register(
            Component.For<IPerson, INotifyPropertyChanged>()
            .ImplementedBy<Person>().LifeStyle.Transient);
    }
}
+3
source share
2 answers

So the answer turned out to be quite simple ... The code http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever defines an interceptor as:

public class NotifyPropertyChangedInterceptor : IInterceptor
{
    private PropertyChangedEventHandler _subscribers = delegate { };

    public void Intercept(IInvocation invocation)
    {
        if (invocation.Method.DeclaringType == typeof(INotifyPropertyChanged))
        {
            HandleSubscription(invocation);
            return;
        }

        invocation.Proceed();

        if (invocation.Method.Name.StartsWith("set_"))
        {
            FireNotificationChanged(invocation);
        }
    }

    private void HandleSubscription(IInvocation invocation)
    {
        var handler = (PropertyChangedEventHandler)invocation.Arguments[0];

        if (invocation.Method.Name.StartsWith("add_"))
        {
            _subscribers += handler;
        }
        else
        {
            _subscribers -= handler;
        }
    }

    private void FireNotificationChanged(IInvocation invocation)
    {
        var propertyName = invocation.Method.Name.Substring(4);
        _subscribers(invocation.InvocationTarget, new PropertyChangedEventArgs(propertyName));
    }
}

In my case, InvocationTarget just wasn't the right entity, which is passed as the first argument to PropertyChanged (because I'm creating a proxy). Changing the last function to the following fixed problem:

private void FireNotificationChanged(IInvocation invocation)
{
    var propertyName = invocation.Method.Name.Substring(4);
    _subscribers(invocation.Proxy, new PropertyChangedEventArgs(propertyName));
}
+4
source

, , Virtual.

0

All Articles