Changeset 4790


Ignore:
Timestamp:
11/15/10 09:41:51 (9 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
Location:
branches/ParameterBinding
Files:
3 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();
  • branches/ParameterBinding/HeuristicLab.Core/3.3/ParameterizedNamedItem.cs

    r4787 r4790  
    2424using HeuristicLab.Common;
    2525using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     26using System.Linq.Expressions;
    2627
    2728namespace HeuristicLab.Core {
     
    3334  public abstract class ParameterizedNamedItem : NamedItem, IParameterizedNamedItem {
    3435    [Storable]
    35     private List<IItemBinding> parameterBindingList;
     36    protected List<IItemBinding> parameterBindingList;
    3637    public List<IItemBinding> ParameterBindingList {
    3738      get { return parameterBindingList; }
     
    5556      : base(original, cloner) {
    5657      parameters = cloner.Clone(original.parameters);
    57       parameterBindingList = original.parameterBindingList.Select(x => cloner.Clone(x)).ToList();
    5858      readOnlyParameters = null;
    5959    }
     
    111111    }
    112112
     113    protected virtual void AddBinding(string targetPath, string sourcePath, LambdaExpression func) {
     114      ItemBinding binding = new ItemBinding(this, targetPath, this, sourcePath, func);
     115      parameterBindingList.Add(binding);
     116      binding.Bind();
     117    }
     118
    113119    protected virtual void AddSourceBinding(IDeepCloneable target, string targetPath, string sourcePath) {
    114120      ItemBinding binding = new ItemBinding(target, targetPath, this, sourcePath);
  • branches/ParameterBinding/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs

    r4787 r4790  
    3333using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    3434using HeuristicLab.PluginInfrastructure;
     35using System.Linq.Expressions;
    3536
    3637namespace HeuristicLab.Problems.TravelingSalesman {
     
    148149    }
    149150    public override IDeepCloneable Clone(Cloner cloner) {
    150       return new TravelingSalesmanProblem(this, cloner);
     151      TravelingSalesmanProblem clone = new TravelingSalesmanProblem(this, cloner);
     152      clone.parameterBindingList = this.parameterBindingList.Select(x => cloner.Clone(x)).ToList();
     153      return clone;
    151154    }
    152155    public TravelingSalesmanProblem()
     
    178181      InitializeOperators();
    179182      AttachEventHandlers();
    180 
     183      CreateBindings();
     184    }
     185
     186    private void CreateBindings() {
     187      #region Analyzers
    181188      AddBinding("BestTSPSolutionAnalyzer.QualityParameter.ActualName", "Evaluator.QualityParameter.ActualName");
    182189      AddBinding("BestTSPSolutionAnalyzer.CoordinatesParameter.ActualName", "CoordinatesParameter.Name");
     
    185192      AddBinding("BestTSPSolutionAnalyzer.BestKnownSolutionParameter.ActualName", "BestKnownSolutionParameter.Name");
    186193      AddBinding("BestTSPSolutionAnalyzer.MaximizationParameter.ActualName", "MaximizationParameter.Name");
    187       BestTSPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
     194      AddBinding("TSPAlleleFrequencyAnalyzer.MaximizationParameter.ActualName", "MaximizationParameter.Name");
     195      AddBinding("TSPAlleleFrequencyAnalyzer.CoordinatesParameter.ActualName", "CoordinatesParameter.Name");
     196      AddBinding("TSPAlleleFrequencyAnalyzer.SolutionParameter.ActualName", "SolutionCreator.PermutationParameter.ActualName");
     197      AddBinding("TSPAlleleFrequencyAnalyzer.QualityParameter.ActualName", "Evaluator.QualityParameter.ActualName");
     198      AddBinding("TSPAlleleFrequencyAnalyzer.BestKnownSolutionParameter.ActualName", "BestKnownSolutionParameter.Name");
     199      AddBinding("TSPPopulationDiversityAnalyzer.MaximizationParameter.ActualName", "MaximizationParameter.Name");
     200      AddBinding("TSPPopulationDiversityAnalyzer.SolutionParameter.ActualName", "SolutionCreator.PermutationParameter.ActualName");
     201      AddBinding("TSPPopulationDiversityAnalyzer.QualityParameter.ActualName", "Evaluator.QualityParameter.ActualName");
     202      #endregion
     203      Expression<Func<IEnumerable<string>,IntValue>> tmp = (x) => new IntValue(x.Count());
     204      AddBinding("SolutionCreator.LengthParameter.Value", "Coordinates.RowNames", tmp);
     205      Expression<Func<IPermutationCreator, PermutationType>> tmp2 = (x) => new PermutationType(PermutationTypes.RelativeUndirected);
     206      AddBinding("SolutionCreator.PermutationTypeParameter.Value", "SolutionCreator", tmp2);
    188207    }
    189208
     
    227246      ParameterizeSolutionCreator();
    228247      ParameterizeEvaluator();
    229       ParameterizeAnalyzers();
    230248      ParameterizeOperators();
    231249      OnSolutionCreatorChanged();
     
    233251    private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
    234252      ParameterizeEvaluator();
    235       ParameterizeAnalyzers();
    236253      ParameterizeOperators();
    237254    }
    238255    private void EvaluatorParameter_ValueChanged(object sender, EventArgs e) {
    239       Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
    240256      ParameterizeEvaluator();
    241257      UpdateMoveEvaluators();
    242       ParameterizeAnalyzers();
    243258      ClearDistanceMatrix();
    244259      OnEvaluatorChanged();
    245     }
    246     private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
    247       ParameterizeAnalyzers();
    248260    }
    249261    private void MoveGenerator_InversionMoveParameter_ActualNameChanged(object sender, EventArgs e) {
     
    278290      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
    279291      EvaluatorParameter.ValueChanged += new EventHandler(EvaluatorParameter_ValueChanged);
    280       Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
    281292    }
    282293
     
    286297      operators.Add(new TSPAlleleFrequencyAnalyzer());
    287298      operators.Add(new TSPPopulationDiversityAnalyzer());
    288       ParameterizeAnalyzers();
     299      BestTSPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
     300      TSPAlleleFrequencyAnalyzer.ResultsParameter.ActualName = "Results";
     301      TSPPopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
    289302      operators.AddRange(ApplicationManager.Manager.GetInstances<IPermutationOperator>().Cast<IOperator>());
    290303      ParameterizeOperators();
     
    314327    }
    315328    private void ParameterizeSolutionCreator() {
    316       SolutionCreator.LengthParameter.Value = new IntValue(Coordinates.Rows);
    317       SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.RelativeUndirected);
     329      //SolutionCreator.LengthParameter.Value = new IntValue(Coordinates.Rows);
     330      //SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.RelativeUndirected);
    318331    }
    319332    private void ParameterizeEvaluator() {
     
    325338        evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
    326339        evaluator.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name;
    327       }
    328     }
    329     private void ParameterizeAnalyzers() {
    330       /*if (BestTSPSolutionAnalyzer != null) {
    331         BestTSPSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
    332         BestTSPSolutionAnalyzer.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
    333         BestTSPSolutionAnalyzer.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
    334         BestTSPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
    335         BestTSPSolutionAnalyzer.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
    336         BestTSPSolutionAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
    337         BestTSPSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
    338       }*/
    339 
    340       if (TSPAlleleFrequencyAnalyzer != null) {
    341         TSPAlleleFrequencyAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
    342         TSPAlleleFrequencyAnalyzer.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
    343         TSPAlleleFrequencyAnalyzer.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
    344         TSPAlleleFrequencyAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
    345         TSPAlleleFrequencyAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
    346         TSPAlleleFrequencyAnalyzer.ResultsParameter.ActualName = "Results";
    347       }
    348 
    349       if (TSPPopulationDiversityAnalyzer != null) {
    350         TSPPopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
    351         TSPPopulationDiversityAnalyzer.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
    352         TSPPopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
    353         TSPPopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
    354340      }
    355341    }
Note: See TracChangeset for help on using the changeset viewer.