Spring AOP的+ MVVM基金会+的PropertyChanged(Spring AOP +

2019-09-28 03:10发布

我用Spring.Net 1.3.1一起MVVM基金会跨领域应用到我的ViewModels。 我发现,如果我指定一个属性更改处理程序之前的对象转换为一个代理相互交叉的代理引擎不属性更改处理程序适用于代理。 有谁知道这是正常现象,如果是的话,如果有解决方法吗?

我厂是这样的

public static class AopProxyFactory {
    public static object GetProxy(object target) {
        var factory = new ProxyFactory(target);

        factory.AddAdvisor(new Spring.Aop.Support.DefaultPointcutAdvisor(
                                new AttributeMatchMethodPointcut(typeof(AttributeStoringMethod)),
                                new UnitValidationBeforeAdvice())
                           );

        factory.AddAdvice(new NotifyPropertyChangedAdvice());
        factory.ProxyTargetType = true;

        return factory.GetProxy();
    }
}

该建议是这样的

    public class UnitValidationBeforeAdvice : IMethodBeforeAdvice {
    public UnitValidationBeforeAdvice() {            
    }

    public void Before(MethodInfo method, object[] args, object target) {
        if (args.Length != 1) {
            throw new ArgumentException("The args collection is not valid!");
        }

        var canConvertTo = true;
        if (!canConvertTo) {
            throw new ArgumentException("The '{0}' cannot be converted.");
        }
    }
}

public class NotifyPropertyChangedAdvice : IAfterReturningAdvice, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    public void AfterReturning(object ReturnValue, MethodInfo Method, object[] Args, object Target) {
        if (Method.Name.StartsWith("set_")) {
            RaisePropertyChanged(Target, Method.Name.Substring("set_".Length));
        }
    }

    private void RaisePropertyChanged(Object Target, String PropertyName) {
        if (PropertyChanged != null)
            PropertyChanged(Target, new PropertyChangedEventArgs(PropertyName));
    }
}

对象我进行代理这个样子的

    public class ProxyTypeObject : ObservableObject {
    private string whoCaresItsBroke;
    public string WhoCaresItsBroke {
        get { return whoCaresItsBroke; }
        set {
            whoCaresItsBroke = value;
            RaisePropertyChanged("WhoCaresItsBroke");
        }
    }
}

和调用代码

var pto = new ProxyTypeObject();
                pto.WhoCaresItsBroke = "BooHoo";
                pto.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => {
                    return;
                };

                var proxy = AopProxyFactory.GetProxy(pto);
                (proxy as ProxyTypeObject).WhoCaresItsBroke = "BooHoo2";

你会发现,当我设置“WhoCaresItsBroke”属性的属性改变处理我之前迷上了永远不会打。 (我尝试使用NotifyPropertyChangedAdvice作为spring.net论坛提供,但不会出现工作。)

Answer 1:

看来,春节例子Spring.AopQuickStart的\ src \ Spring.AopQuickStart.Step6做几乎你正在尝试做的(拦截产权[自动生成]二传手)的samething。 你可能想看看该示例的源 。



Answer 2:

你应该申报WhoCaresItsBroke属性作为虚拟的,否则也不会被你的代理对象覆盖。 使得虚拟都会对你的处理器pto再次调用,因为代理将委托财产呼吁其目标。

你不需要NotifyPropertyChangedAdvice ,你可以将其删除。 期望的行为已经由实施ObservableObject你使用类。

如果您希望PropertyChanged事件对代理当目标被解雇PropertyChanged事件被触发,你应该手动实现这一点,因为在下面的技巧建议。

黑客或替代方法火灾PropertyChanged对代理目标

一个ProxyFactory里没有电线目标事件到代理类似的活动,但你可以手动执行此操作。 我不知道我是否会建议你这样做,但你可以使用下面的技巧。

重写你的代理工厂和ProxyTypeObject

public class ProxyTypeObject : ObservableObject
{
    private string whoCaresItsBroke;
    // step 1:
    // make the property virtual, otherwise it will not be overridden by the proxy
    public virtual string WhoCaresItsBroke
    {
      // original implementation
    }

    public void PublicRaisePropertyChanged(string name)
    {
        RaisePropertyChanged(name);
    }
}

public static class AopProxyFactory
{
    public static object GetProxy(object target)
    {
        ProxyFactory factory = GetFactory(target);

        object proxy = factory.GetProxy();

        if(target is ProxyTypeObject)
        {
            // step 2:
            // hack: hook handlers ...
            var targetAsProxyTypeObject = (ProxyTypeObject)target;
            var proxyAsProxyTypeObject = (ProxyTypeObject)proxy;
            HookHandlers(targetAsProxyTypeObject, proxyAsProxyTypeObject);
        }

        return proxy;

    }

    private static void HookHandlers(ProxyTypeObject target, ProxyTypeObject proxy)
    {
        target.PropertyChanged += (sender, e) =>
        {
            proxy.PublicRaisePropertyChanged(e.PropertyName);
        };
    }

    private static ProxyFactory GetFactory(object target)
    {
        var factory = new ProxyFactory(target);
        // I simply add the advice here, but you could useyour original
        //  factory.AddAdvisor( ... )
        factory.AddAdvice(new UnitValidationBeforeAdvice());
        // You don't need this:
        // factory.AddAdvice(new NotifyPropertyChangedAdvice()); 
        factory.ProxyTargetType = true;
        return factory;
    }
}

这就要求ProxyTypeObject有一个公开可见的方法来筹集PropertyChangedEvent ; 你或许应该这样做不同的,但是这是除了点。

这个怎么运作

该工厂返回类型的代理ProxyTypeObject ,因为你已经设置factory.ProxyTargetType = true; 。 它仍然是基于组成的代理,但:进行代理,你将有原来的对象(目标) 新的代理对象之后。 双方代理和目标的类型的ProxyTypeObject ,可以提高一个PropertyChanged事件。

在这个阶段,当设置WhoCaresItsBroke上的代理,该PropertyChanged事件将触发对您的代理,而不是目标。 target属性不会改变。

步骤1:声明属性作为虚拟

因为我们已经取得的财产WhoCaresItsBroke虚拟的,它可以在代理所覆盖。 在重写的财产,代理对象代表所有WhoCaresItsBroke调用到WhoCaresItsBroke属性为目标。

此步骤后,你会看到你连接到你原来的处理程序pto实例调用。 然而, PropertyChanged是不是提高了对代理事件。

步骤2:钩目标事件对代理处理程序

只需简单勾目标PropertyChanged事件处理程序上提出了自己的代理服务器PropertyChanged事件。 我们可以使用相同的名称,因为在代理,我们可以假设我们是同一类型的。



文章来源: Spring AOP + MVVM Foundation + PropertyChanged