Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
11/15/10 09:41:51 (14 years ago)
Author:
abeham
Message:

#1258

  • Added detection if a certain link in the chain implements INotifyPropertyChanged (still missing -> fire only on a change to the "right" property)
  • Added optional parameter LambdaExpression in the binding
  • Changed cloning behavior of binding -> bindings have to be cloned only after the clone is fully constructed
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/ParameterBinding/HeuristicLab.Core/3.3/ItemBinding.cs

    r4788 r4790  
    77using System.Reflection;
    88using System.Reflection.Emit;
     9using System.ComponentModel;
     10using System.Linq.Expressions;
    911
    1012namespace HeuristicLab.Core {
     
    2224    [Storable]
    2325    private bool bound;
    24 
     26    [Storable]
     27    private LambdaExpression bindingExpression;
     28
     29    private Delegate bindingFunc;
    2530    private static object evhCacheLock = new object();
    2631    private static Dictionary<Type, DynamicMethod> eventHandlerCache = new Dictionary<Type, DynamicMethod>();
     
    3338      this.source = cloner.Clone(original.source);
    3439      this.sourcePath = original.sourcePath;
     40      this.bindingExpression = original.bindingExpression;
     41      if (this.bindingExpression != null)
     42        this.bindingFunc = this.bindingExpression.Compile();
    3543      if (original.bound) Bind();
    3644    }
     
    4250      this.bound = false;
    4351    }
     52    public ItemBinding(IDeepCloneable target, string targetPath, IDeepCloneable source, string sourcePath, LambdaExpression func)
     53      : this(target, targetPath, source, sourcePath) {
     54      this.bindingExpression = func;
     55      this.bindingFunc = this.bindingExpression.Compile();
     56    }
    4457
    4558    public IDeepCloneable Clone(Cloner cloner) {
     
    5467    private void AfterDeserialization() {
    5568      if (bound) RegisterEventHandlers();
     69      if (bindingExpression != null)
     70        bindingFunc = bindingExpression.Compile();
    5671    }
    5772
     
    7186      object current = source;
    7287      foreach (string property in properties) {
    73         TryHookToChangedEvent(current, property + "Changed");
     88        TryHookToChangedEvent(current, property);
    7489        MethodInfo mInfo = current.GetType().GetProperty(property, Flags).GetGetMethod(true);
    7590        object next = mInfo.Invoke(current, null);
     
    8398      object current = source;
    8499      foreach (string property in properties) {
    85         TryUnhookFromChangedEvent(current, property + "Changed");
     100        TryUnhookFromChangedEvent(current, property);
    86101        MethodInfo mInfo = current.GetType().GetProperty(property, Flags).GetGetMethod(true);
    87102        object next = mInfo.Invoke(current, null);
     
    95110      string[] sourceProperties = sourcePath.Split('.');
    96111      object cSource = source;
    97       #region Navigate to source property
     112      #region Navigate to source property (readd bindings if necessary)
    98113      bool reregister = false;
    99114      for (int i = 0; i < sourceProperties.Length; i++) {
    100115        if (cSource == null) return;
    101116        string property = sourceProperties[i];
    102         if (reregister) TryHookToChangedEvent(cSource, property + "Changed");
     117        if (reregister) TryHookToChangedEvent(cSource, property);
    103118        if (cSource == sender) reregister = true;
    104         object next = cSource.GetType().GetProperty(property, Flags).GetGetMethod(true).Invoke(cSource, null);
     119        PropertyInfo pInfo = cSource.GetType().GetProperty(property, Flags);
     120        if (pInfo == null) return;
     121        object next = pInfo.GetGetMethod(true).Invoke(cSource, null);
    105122        cSource = next;
    106123      }
     
    112129      #region Navigate to target property
    113130      for (int i = 0; i < targetProperties.Length - 1; i++) {
    114         cTarget = cTarget.GetType().GetProperty(targetProperties[i], Flags).GetGetMethod(true).Invoke(cTarget, null);
     131        PropertyInfo pInfo = cTarget.GetType().GetProperty(targetProperties[i], Flags);
     132        if (pInfo == null) return;
     133        cTarget = pInfo.GetGetMethod(true).Invoke(cTarget, null);
    115134        if (cTarget == null) return;
    116135      }
     
    119138      #endregion
    120139
    121       if (cSource == null && !targetSetter.GetParameters().First().ParameterType.IsValueType
     140      if (bindingFunc != null) {
     141        targetSetter.Invoke(cTarget, new object[] { bindingFunc.DynamicInvoke(new object[] { cSource }) });
     142      } else if (cSource == null && !targetSetter.GetParameters().First().ParameterType.IsValueType
    122143        || cSource != null && cSource.GetType().IsValueType)
    123144        targetSetter.Invoke(cTarget, new object[] { cSource });
     
    128149
    129150    private bool TryHookToChangedEvent(object obj, string property) {
    130       EventInfo eInfo = obj.GetType().GetEvent(property, Flags);
    131       if (eInfo != null) {
    132         Type[] methodParams = eInfo.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
    133         if (!eventHandlerCache.ContainsKey(methodParams[1]))
    134           CreateAndAddDynamicEventHandler(eInfo, methodParams);
    135         eInfo.AddEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
    136       }
    137       return eInfo != null;
     151      INotifyPropertyChanged npc = (obj as INotifyPropertyChanged);
     152      if (npc != null) {
     153        npc.PropertyChanged += new PropertyChangedEventHandler(source_PropertyChanged);
     154        return true;
     155      } else {
     156        EventInfo eInfo = obj.GetType().GetEvent(property + "Changed", Flags);
     157        if (eInfo != null) {
     158          Type[] methodParams = eInfo.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
     159          if (!eventHandlerCache.ContainsKey(methodParams[1]))
     160            CreateAndAddDynamicEventHandler(eInfo, methodParams);
     161          eInfo.AddEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
     162        }
     163        return eInfo != null;
     164      }
    138165    }
    139166
    140167    private bool TryUnhookFromChangedEvent(object obj, string property) {
    141       EventInfo eInfo = obj.GetType().GetEvent(property, Flags);
    142       if (eInfo != null) {
    143         Type[] methodParams = eInfo.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
    144         if (eventHandlerCache.ContainsKey(methodParams[1]))
    145           eInfo.RemoveEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
    146       }
    147       return eInfo != null;
     168      INotifyPropertyChanged npc = (obj as INotifyPropertyChanged);
     169      if (npc != null) {
     170        npc.PropertyChanged -= new PropertyChangedEventHandler(source_PropertyChanged);
     171        return true;
     172      } else {
     173        EventInfo eInfo = obj.GetType().GetEvent(property, Flags);
     174        if (eInfo != null) {
     175          Type[] methodParams = eInfo.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
     176          if (eventHandlerCache.ContainsKey(methodParams[1]))
     177            eInfo.RemoveEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
     178        }
     179        return eInfo != null;
     180      }
     181    }
     182
     183    private void source_PropertyChanged(object sender, PropertyChangedEventArgs e) {
     184      ExecuteBinding(sender);
    148185    }
    149186
     
    152189        if (!eventHandlerCache.ContainsKey(methodParams[1])) {
    153190          Type[] instanceMethodParams = new Type[] { GetType() }.Concat(methodParams).ToArray();
    154           DynamicMethod dynamicEventHandler = new DynamicMethod("sourceChanged", null, instanceMethodParams, GetType());
     191          DynamicMethod dynamicEventHandler = new DynamicMethod("source_Changed", null, instanceMethodParams, GetType());
    155192          MethodInfo executeBindingMethodInfo = GetType().GetMethod("ExecuteBinding", Flags);
    156193          ILGenerator iLG = dynamicEventHandler.GetILGenerator();
Note: See TracChangeset for help on using the changeset viewer.