2010-11-29 41 views
2

http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx fournit un exemple d'implémentation de IInterceptionBehavior pour ajouter le support INotifyPropertyChanged. Ce que l'exemple ne comprend pas, c'est comment configurer NotifyPropertyChangedBehavior pour être utilisé lors de l'exécution. Tout le googling que j'ai fait ne m'a pas donné une réponse de travail. Je suis nouveau à l'AOP et à l'IoC donc peut-être que j'ai aussi le concept faux. Voilà ce que je veux faire:Comment configurer Unity 2.0 à l'exécution pour intercepter INotifyPropertyChanged?

using Microsoft.Practices.Unity; 
using Microsoft.Practices.Unity.InterceptionExtension; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Reflection; 

static class AppMain 
{ 
    public static void Main() 
    { 
     // Configure Unity. 
     var container = new UnityContainer(); 

     container.AddNewExtension<Interception>(); 

     // todo: Register an interface instead of a type. 
     container.RegisterType<Customer>(new Interceptor<VirtualMethodInterceptor>(), 
             new InterceptionBehavior<NotifyPropertyChangedBehavior>()); 

     var propertyChangedCount = 0; 
     var customer = new Customer(); 

     customer.PropertyChanged += (s, e) => propertyChangedCount += 1; 

     // Update customer and send property changed event. 
     customer.FirstName = "what ever"; 

     if (propertyChangedCount != 1) 
     { 
      Console.Write("Failed!"); 
     } 
     else 
     { 
      Console.WriteLine("Success!"); 
     } 

     Console.WriteLine(); 
     Console.WriteLine("Press any key to continue..."); 
     Console.ReadKey(); 

    } 

    static void customer_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     throw new NotImplementedException(); 
    } 

    public class Customer : MarshalByRefObject, INotifyPropertyChanged 
    { 

     private string _firstName; 
     public event PropertyChangedEventHandler PropertyChanged; 

     // todo: Does the property have to be virtual (overridable). 
     public virtual string FirstName 
     { 
      get { return _firstName; } 
      set 
      { 
       _firstName = value; 
       // Unity Interception to do the following RaiseEvent 
       //if (PropertyChanged != null) 
       //{ 
       // PropertyChanged(this, new PropertyChangedEventArgs("FirstName")); 
       //} 
      } 
     } 

    } 

    // Copied from http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx 
    class NotifyPropertyChangedBehavior : IInterceptionBehavior 
    { 
     private event PropertyChangedEventHandler propertyChanged; 

     private static readonly MethodInfo addEventMethodInfo = 
      typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetAddMethod(); 

     private static readonly MethodInfo removeEventMethodInfo = 
      typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetRemoveMethod(); 

     public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) 
     { 
      if (input.MethodBase == addEventMethodInfo) 
      { 
       return AddEventSubscription(input, getNext); 
      } 
      if (input.MethodBase == removeEventMethodInfo) 
      { 
       return RemoveEventSubscription(input, getNext); 
      } 
      if (IsPropertySetter(input)) 
      { 
       return InterceptPropertySet(input, getNext); 
      } 
      return getNext()(input, getNext); 
     } 

     public bool WillExecute 
     { 
      get { return true; } 
     } 

     public IEnumerable<Type> GetRequiredInterfaces() 
     { 
      return new[] { typeof(INotifyPropertyChanged) }; 
     } 

     private IMethodReturn AddEventSubscription(IMethodInvocation input, 
                GetNextInterceptionBehaviorDelegate getNext) 
     { 
      var subscriber = (PropertyChangedEventHandler)input.Arguments[0]; 

      propertyChanged += subscriber; 
      return input.CreateMethodReturn(null); 
     } 

     private IMethodReturn RemoveEventSubscription(IMethodInvocation input, 
                 GetNextInterceptionBehaviorDelegate getNext) 
     { 
      var subscriber = (PropertyChangedEventHandler)input.Arguments[0]; 

      propertyChanged -= subscriber; 
      return input.CreateMethodReturn(null); 
     } 

     private static bool IsPropertySetter(IMethodInvocation input) 
     { 
      return input.MethodBase.IsSpecialName && input.MethodBase.Name.StartsWith("set_"); 
     } 

     private IMethodReturn InterceptPropertySet(IMethodInvocation input, 
                GetNextInterceptionBehaviorDelegate getNext) 
     { 
      var propertyName = input.MethodBase.Name.Substring(4); 
      var returnValue = getNext()(input, getNext); 
      var subscribers = propertyChanged; 

      if (subscribers != null) 
      { 
       subscribers(input.Target, new PropertyChangedEventArgs(propertyName)); 
      } 

      return returnValue; 
     } 
    } 
} 

Répondre

1

Il est here et here. En gros, vous devez vous enregistrer le type et l'intercepteur:

Dim container As IUnityContainer = New UnityContainer() 
    container.AddNewExtension(Of Interception)() 
    container.RegisterType(Of Customer)(_ 
      New Interceptor(Of VirtualMethodInterceptor)(), _ 
      New InterceptionBehavior(Of NotifyPropertyChangedBehavior)()) 
+0

Votre code compile et fonctionne apparemment, mais l'événement PropertyChanged n'est pas soulevé par le client comme prévu . J'ai changé le code source en C#. Cela semble conduire à plus de personnes lisant un message. –

+0

Trouvé l'erreur, l'intercepteur doit être TransparentProxyInterceptor, pas VirtualMethodInterceptor. – onof

0

J'ai besoin d'utiliser VirtualMethodInterceptor. J'ai trouvé le NotifyPropertyChangedBehavior.Invoke vérifier pour un PropertyChanged ajouter ou supprimer n'a jamais été vrai. J'ai changé pour vérifier une correspondance de nom de méthode et les choses fonctionnent.

Le NotifyPropertyChangedBehavior original provient de la documentation Unity sur msdn. Je suis intéressé si quelqu'un peut me dire pourquoi le code original ne fonctionne pas.

classe Définition

public class NotifyPropertyChangeClass 
    : INotifyPropertyChanged 
{ 
    public virtual int SomeInt { get; set; } 

    public virtual event PropertyChangedEventHandler PropertyChanged; 
} 

IUnityContainer Configuration

container.AddNewExtension<Interception>(); 
container.RegisterType<NotifyPropertyChangeClass>(
    new Interceptor<VirtualMethodInterceptor>(), 
    new InterceptionBehavior(new NotifyPropertyChangedBehavior())); 

modification NotifyPropertyChangedBehavior (original)

public class NotifyPropertyChangedBehavior : IInterceptionBehavior 
{ 
... 
    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) 
    { 
     if (input.MethodBase.Name.Equals(addEventMethodInfo.Name))//(input.MethodBase == addEventMethodInfo) 
     { 
      return AddEventSubscription(input, getNext); 
     } 
     if (input.MethodBase.Name.Equals(removeEventMethodInfo.Name))//(input.MethodBase == removeEventMethodInfo) 
     { 
      return RemoveEventSubscription(input, getNext); 
     } 
     if (IsPropertySetter(input)) 
     { 
      return InterceptPropertySet(input, getNext); 
     } 
     return getNext()(input, getNext); 
    } 
... 
}