Castle Windsor 代理、隐式接口和 WPF 绑定

发布于 2024-11-05 07:20:00 字数 1616 浏览 1 评论 0原文

我正在尝试使用 Castle Windsor 动态代理实现 WPF ViewModel。我的想法是,我想提供一个接口(下面的 IPerson 应该足以作为示例)、一个具体的支持类和一个拦截器(用于提供 INotifyPropertyChanged 的​​自动实现)。拦截器实现在这里: http://www.hightech.ir/SeeSharp /Best-Implementation-Of-INotifyPropertyChange-Ever

我看到的问题是,当我将模型绑定到 WPF 控件时,控件不会将模型视为实现 INotifyPropertyChanged。我相信(但不确定)这是因为 Windsor 显式实现了接口,而 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);
    }
}

I am attempting to implement a WPF ViewModel using Castle Windsor Dynamic Proxies. The idea is that I want to supply an interface (IPerson below should suffice as an example), a concrete backing class, and an interceptor (for providing automatic implementation of INotifyPropertyChanged). The interceptor implementation is here: http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever

The problem that I am seeing is that when I bind my models to WPF controls, the controls don't see the models as implementing INotifyPropertyChanged. I believe (but am not sure) that this is because Windsor is implementing the interfaces explicitly, and WPF seems to expect them to be implicit.

Is there any way to make this work, so that changes to the model are caught by the interceptor and raised to the model?

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

Code is as follows:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花之痕靓丽 2024-11-12 07:20:00

所以答案相当简单......来自 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));
    }
}

在我的情况下,InvocableTarget 根本不是正确的实体作为第一个参数传递给 PropertyChanged (因为我正在生成代理)。将最后一个函数更改为以下内容解决了问题:

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

So the answer turned out to be fairly straightforward... The code from http://www.hightech.ir/SeeSharp/Best-Implementation-Of-INotifyPropertyChange-Ever defines the 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, the InvocationTarget was simply not the right entity to be passing as the first argument to PropertyChanged (because I am generating a proxy). Changing the last function to the following fixed the problem:

private void FireNotificationChanged(IInvocation invocation)
{
    var propertyName = invocation.Method.Name.Substring(4);
    _subscribers(invocation.Proxy, new PropertyChangedEventArgs(propertyName));
}
平生欢 2024-11-12 07:20:00

我认为您需要使实现虚拟接口的类的成员成为可能。

I think you need to make the members of your Class that implements the interface Virtual.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文