Implementing INotifyPropertyChanged - does a better way exist?

前端 未结 30 2690
感情败类
感情败类 2020-11-21 05:23

Microsoft should have implemented something snappy for INotifyPropertyChanged, like in the automatic properties, just specify {get; set; notify;} I

30条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-11-21 05:44

    Yes, better way certainly exists. Here it is:

    Step by step tutorial shrank by me, based on this useful article.

    • Create new project
    • Install castle core package into the project

    Install-Package Castle.Core

    • Install mvvm light libraries only

    Install-Package MvvmLightLibs

    • Add two classes in project:

    NotifierInterceptor

    public class NotifierInterceptor : IInterceptor
        {
            private PropertyChangedEventHandler handler;
            public static Dictionary _cache =
              new Dictionary();
    
            public void Intercept(IInvocation invocation)
            {
                switch (invocation.Method.Name)
                {
                    case "add_PropertyChanged":
                        handler = (PropertyChangedEventHandler)
                                  Delegate.Combine(handler, (Delegate)invocation.Arguments[0]);
                        invocation.ReturnValue = handler;
                        break;
                    case "remove_PropertyChanged":
                        handler = (PropertyChangedEventHandler)
                                  Delegate.Remove(handler, (Delegate)invocation.Arguments[0]);
                        invocation.ReturnValue = handler;
                        break;
                    default:
                        if (invocation.Method.Name.StartsWith("set_"))
                        {
                            invocation.Proceed();
                            if (handler != null)
                            {
                                var arg = retrievePropertyChangedArg(invocation.Method.Name);
                                handler(invocation.Proxy, arg);
                            }
                        }
                        else invocation.Proceed();
                        break;
                }
            }
    
            private static PropertyChangedEventArgs retrievePropertyChangedArg(String methodName)
            {
                PropertyChangedEventArgs arg = null;
                _cache.TryGetValue(methodName, out arg);
                if (arg == null)
                {
                    arg = new PropertyChangedEventArgs(methodName.Substring(4));
                    _cache.Add(methodName, arg);
                }
                return arg;
            }
        }
    

    ProxyCreator

    public class ProxyCreator
    {
        public static T MakeINotifyPropertyChanged() where T : class, new()
        {
            var proxyGen = new ProxyGenerator();
            var proxy = proxyGen.CreateClassProxy(
              typeof(T),
              new[] { typeof(INotifyPropertyChanged) },
              ProxyGenerationOptions.Default,
              new NotifierInterceptor()
              );
            return proxy as T;
        }
    }
    
    • Create your view model, for example:

    -

     public class MainViewModel
        {
            public virtual string MainTextBox { get; set; }
    
            public RelayCommand TestActionCommand
            {
                get { return new RelayCommand(TestAction); }
            }
    
            public void TestAction()
            {
                Trace.WriteLine(MainTextBox);
            }
        }
    
    • Put bindings into xaml:

      
      
      
    • Put line of code in code-behind file MainWindow.xaml.cs like this:

    DataContext = ProxyCreator.MakeINotifyPropertyChanged();

    • Enjoy.

    enter image description here

    Attention!!! All bounded properties should be decorated with keyword virtual because they used by castle proxy for overriding.

提交回复
热议问题