2010-11-29 32 views
2

http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx提供了一個如何實現IInterceptionBehavior以添加INotifyPropertyChanged支持的示例。該示例不包括的是如何配置NotifyPropertyChangedBehavior以在運行時使用。我所做的所有Google搜索都沒有給我一個有效的答案。如何在運行時配置Unity 2.0以截獲INotifyPropertyChanged?

我是AOP和IoC的新手,所以也許我的概念也錯了。這就是我想做的事:

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

回答

1

這是herehere。基本上,你必須註冊類型和攔截器:

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

你的代碼編譯,看似運行,但PropertyChanged事件不是由客戶提出。我已將源代碼更改爲c#。這似乎導致更多人閱讀帖子。 – 2010-11-29 16:21:33

0

我需要使用VirtualMethodInterceptor。我發現NotifyPropertyChangedBehavior.Invoke檢查PropertyChanged添加或刪除從未如此。我改變檢查方法名稱匹配和事情工作。

原始NotifyPropertyChangedBehavior來自msdn上的Unity文檔。如果有人能告訴我爲什麼原始代碼不起作用,我很感興趣。

類定義

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

    public virtual event PropertyChangedEventHandler PropertyChanged; 
} 

IUnityContainer設置如預期

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

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