Castle Windsor прокси, неявные интерфейсы и WPF Binding - PullRequest
3 голосов
/ 07 мая 2011

Я пытаюсь реализовать WPF ViewModel, используя Castle Windsor Dynamic Proxies. Идея заключается в том, что я хочу предоставить интерфейс (ниже приведен IPerson), конкретный класс поддержки и перехватчик (для обеспечения автоматической реализации INotifyPropertyChanged). Реализация перехватчика здесь: http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever

Проблема, с которой я сталкиваюсь, заключается в том, что когда я связываю свои модели с элементами управления WPF, элементы управления не видят модели как реализующие INotifyPropertyChanged. Я полагаю (но не уверен), что это потому, что Виндзор явно реализует интерфейсы, и WPF, похоже, ожидает, что они будут неявными.

Есть ли способ заставить эту работу так, чтобы изменения в модели были перехвачены перехватчиком и переданы в модель?

Все версии библиотек являются самыми последними: Castle.Core 2.5.1.0 и Windsor 2.5.1.0

Код выглядит следующим образом:

// My model's 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);
    }
}

Ответы [ 2 ]

4 голосов
/ 09 мая 2011

Таким образом, ответ оказался довольно простым ... Код от http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever определяет перехватчик как:

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));
    }
}

В моем случае InvocationTarget просто не был правильным объектомчтобы передать в качестве первого аргумента PropertyChanged (потому что я генерирую прокси).Изменение последней функции на следующую решило проблему:

private void FireNotificationChanged(IInvocation invocation)
{
    var propertyName = invocation.Method.Name.Substring(4);
    _subscribers(invocation.Proxy, new PropertyChangedEventArgs(propertyName));
}
0 голосов
/ 07 мая 2011

Я думаю, вам нужно сделать членов вашего класса, который реализует интерфейс Virtual.

...