2011-04-29 1 views
1

MVVM Foundation과 함께 Spring.Net 1.3.1을 사용하여 내 viewmodels에 교차 절단을 적용하고 있습니다. 객체가 크로스 커팅 (cross-cutting)을 위해 프록시로 변환되기 전에 프록시가 속성 변경 핸들러를 프록시에 적용하지 않기 전에 프로퍼티 변경 핸들러를 할당했다는 것을 알았습니다. 아무도 이것이 예상되는 동작인지 그리고 만약 그렇다면 해결 방법이 있는지 알고 있습니까?봄 AOP + MVVM 재단 + PropertyChanged

는 내 공장은 조언 내가이

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

같은 모양과 호출 코드를 프록시있어이

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

처럼 보이는

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를 사용했으나 작동하지 않는 것으로 나타났습니다.)

+1

"AttributeMatchMethodPointcut (typeof (AttributeStoringMethod)"를 정의하고 있지만 "AttributeStoringMethod"-Attribut을 사용하여 어떤 메소드가 pointcuts인지 표시하지 않습니다. 실제로 해당 속성을 사용하고있는 코드 부분을 게시 할 수 있습니까? – tobsen

답변

0

Spring 예제 Spring.AopQuickStart \ src \ Spring.AopQuickStart.Step6은 여러분이 가지고있는 거의 모든 것을 수행하는 것으로 보입니다. (속성의 [자동 생성] 설정자를 가로채는) 시도. the source of the example을보고 싶을 수 있습니다.

+1

나는 이것이 OP의 문제라고 생각하지 않는다. 나는'WhoCaresItsBroke' 속성이 가상이 아니기 때문에 프록시에 의해 오버라이드되지 않기 때문에 user327911이 그의 목표 객체의 속성 설정자가 결코 호출되지 않는다고 생각한다. 프록시는 결코 목표에 호출을 위임하지 않고 자신의 속성을 설정합니다. 어떻게 생각하십니까 – Marijn

+0

속성이 가상이어야합니다 (링크 된 스프링 예제에서와 같이). "AttributeStoringMethod "- setter에 대해 알리거나 그렇지 않으면 pointcut에 대해 ProxyFactory에 알리십시오. – tobsen

0

WhoCaresItsBroke 속성을 가상으로 선언해야합니다. 그렇지 않으면 프록시 개체가 재정의하지 않습니다. 가상으로 만들면 pto에있는 처리기가 다시 호출됩니다. 프록시는 속성 호출을 대상에 위임하기 때문입니다.

NotifyPropertyChangedAdvice이 필요하지 않은 경우 제거 할 수 있습니다. 원하는 동작은 이미 사용중인 ObservableObject 클래스에서 구현됩니다.

대상 PropertyChanged 이벤트가 발생하면 PropertyChanged 이벤트가 프록시에서 실행되도록하려면 다음 해킹에서 제안하는 것처럼 직접 구현해야합니다.

프록시 대상에 PropertyChanged을 발사 할 수있는 해킹 또는 해결 방법

ProxyFactory에는 프록시 비슷한 이벤트에 배선하지 대상 이벤트 않지만, 수동으로이 작업을 수행 할 수 있습니다. 내가 조언을 할 수 있을지 잘 모르겠지만 다음과 같은 해킹을 사용할 수 있습니다.

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

이것은 PropertyChangedEvent을 올릴 수있는 공개 방법을 가지고 ProxyTypeObject을 요구한다 :

는 프록시 공장과 ProxyTypeObject를 다시 작성

당신은 아마 이것을 다르게해야하지만 그것은 요점 외에도 있습니다. 당신이 factory.ProxyTargetType = true;를 설정 때문에이

공장을 작동하는 방법

는 입력 ProxyTypeObject의 프록시를 반환합니다.그래도 여전히 컴포지션 기반 프록시입니다. 프록시 후에는 원래 대상 (대상) 새 프록시 개체가 있습니다. 프록시와 대상 모두 ProxyTypeObject 유형이며 PropertyChanged 이벤트를 발생시킬 수 있습니다.

이 단계에서 프록시에 WhoCaresItsBroke을 설정하면 프록시에서 PropertyChanged 이벤트가 발생하지만 대상에는 발생하지 않습니다. 대상 속성은 변경되지 않습니다.

1 단계 : 우리가 재산 가상 WhoCaresItsBroke을했습니다 때문에 가상

로 속성을 선언, 그것은 프록시에서 재정의 할 수 있습니다. 재정의 된 속성에서 프록시 개체는 WhoCaresItsBroke 속성에 대한 모든 WhoCaresItsBroke 호출을 대상에 위임합니다.

이 단계가 끝나면 pto 인스턴스에 첨부 한 원래 핸들러가 호출 된 것을 볼 수 있습니다. 그러나 프록시의 PropertyChanged 이벤트는 발생하지 않습니다.

2 단계 :

프록시

의 핸들러에 후크 대상 이벤트는 간단하게 자신의 PropertyChanged 이벤트를 발생 프록시의 처리기에 대상 PropertyChanged 이벤트를 후크. 우리는 같은 이름을 사용할 수 있습니다. 프록시에서 우리는 우리가 같은 유형이라고 가정 할 수 있기 때문입니다.