Spring AOP + MVVM基础+ PropertyChanged [英] Spring AOP + MVVM Foundation + PropertyChanged

查看:67
本文介绍了Spring AOP + MVVM基础+ PropertyChanged的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Spring.Net 1.3.1与MVVM Foundation一起使用,将横切应用于我的视图模型.我注意到,如果在将对象转换为代理进行跨切之前分配了属性更改的处理程序,则代理引擎不会将属性更改的处理程序应用于代理.有谁知道这是否是预期的行为,如果是,是否有解决方法?

I'm using Spring.Net 1.3.1 alongside MVVM Foundation to apply cross-cutting to my viewmodels. I've noticed that if I assign a property changed handler before the object is converted to a proxy for cross-cutting that the proxy engine does not apply the property changed handler to the proxy. Does anyone know if this is expected behavior and if so, if there is a workaround?

我的工厂看起来像这样

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

我代理的对象看起来像这样

The object I'm proxying look like this

    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"属性时,我以前连接的属性更改处理程序永远不会被击中. (我尝试使用spring.net论坛中提供的NotifyPropertyChangedAdvice,但似乎不起作用.)

You will notice that when I set the "WhoCaresItsBroke" property the property changed handler I previously hooked up is never hit. (I tried using the NotifyPropertyChangedAdvice as provided in the spring.net forums but that does not appear to work.)

推荐答案

您应将WhoCaresItsBroke属性声明为虚拟属性,否则它将不被您的代理对象覆盖.将其设置为虚拟会导致pto上的处理程序再次被调用,因为代理会将属性调用委派给其目标.

You should declare the WhoCaresItsBroke property as virtual, otherwise it will not be overridden by your proxy object. Making it virtual will cause your handler on pto to be called again, because the proxy will delegate the property call to its target.

您不需要NotifyPropertyChangedAdvice,可以将其删除.您所使用的ObservableObject类已经实现了所需的行为.

You do not need the NotifyPropertyChangedAdvice, you can remove it. The desired behavior is already implemented by the ObservableObject class you're using.

如果您希望在触发目标PropertyChanged事件时在代理上触发PropertyChanged事件,则应按照以下技巧中的建议手动执行此操作.

If you want the PropertyChanged event to be fired on the proxy when the target PropertyChanged event is fired, you should implement this manually, as suggested in the following hack.

要在代理目标上触发PropertyChanged的黑客或替代方法

The hack or workaround to fire PropertyChanged on proxy and the target

proxyfactory不会将目标事件连接到代理上的类似事件,但是您可以手动执行此操作.我不确定是否会建议您这样做,但是您可以使用以下技巧.

A proxyfactory does not wire target events to similar event on a proxy, but you could do this manually. I'm not sure if I would advice you to do so, but you could use the following hack.

重写您的代理工厂和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;您可能应该以不同的方式执行此操作,但这不重要.

This requires ProxyTypeObject to have a publicly visible method to raise a PropertyChangedEvent; you probably should do this differently, but that's besides the point.

工作原理

工厂已返回类型为ProxyTypeObject的代理,因为您已设置factory.ProxyTargetType = true;.但是,它仍然是基于组合的代理:代理后,您将拥有原始对象(目标)新代理对象.代理服务器和目标服务器都属于ProxyTypeObject类型,并且可以引发PropertyChanged事件.

The factory returns a proxy of type ProxyTypeObject, because you have set factory.ProxyTargetType = true;. It is still a composition based proxy though: after proxying you will have the original object (the target) and the new proxy object. Both proxy and target are of type ProxyTypeObject and can raise a PropertyChanged event.

在此阶段,在代理上设置WhoCaresItsBroke时,PropertyChanged事件将在您的代理上触发,但不会在目标上触发.目标属性未更改.

At this stage, when setting WhoCaresItsBroke on the proxy, the PropertyChanged event will fire on your proxy, but not on the target. The target property is not changed.

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

step 1: declare property as virtual

由于我们已将属性WhoCaresItsBroke设为虚拟,因此可以在代理中覆盖它.在重写属性中,代理对象将对WhoCaresItsBroke属性的所有WhoCaresItsBroke调用委托给目标.

Because we've made the property WhoCaresItsBroke virtual, it can be overridden in the proxy. In the overridden property, the proxy object delegates all WhoCaresItsBroke calls to the WhoCaresItsBroke property to the target.

此步骤之后,您将看到调用附加到pto实例的原始处理程序.但是,不会引发代理上的PropertyChanged事件.

After this step, you'll see that the original handler you attached to your pto instance is called. However, the PropertyChanged event on the proxy is not raised.

第2步:将目标事件挂接到代理上的处理程序

step 2: hook target event to a handler on proxy

只需将目标PropertyChanged事件挂接到引发它自己的PropertyChanged事件的代理上的处理程序.我们可以使用相同的名称,因为在代理中我们可以假定我们属于同一类型.

Simply hook the target PropertyChanged event to a handler on the proxy that raises its own PropertyChanged event. We can use the same name because in the proxy we can assume we're of the same type.

这篇关于Spring AOP + MVVM基础+ PropertyChanged的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆