Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization/3.3/RunCollection.cs @ 11982

Last change on this file since 11982 was 11345, checked in by abeham, 10 years ago

#2120: fixed event handling

File size: 22.1 KB
RevLine 
[3260]1#region License Information
2/* HeuristicLab
[11171]3 * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3260]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
[3329]22using System;
[3260]23using System.Collections.Generic;
[11344]24using System.ComponentModel;
[3260]25using System.Linq;
[4068]26using HeuristicLab.Collections;
[3376]27using HeuristicLab.Common;
[3260]28using HeuristicLab.Core;
[3329]29using HeuristicLab.Data;
[3260]30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31
32namespace HeuristicLab.Optimization {
[3716]33  [Item("Run Collection", "Represents a collection of runs.")]
34  [Creatable("Testing & Analysis")]
[3260]35  [StorableClass]
[4419]36  public class RunCollection : ItemCollection<IRun>, IStringConvertibleMatrix, IStorableContent {
37    public string Filename { get; set; }
38
[4164]39    [StorableConstructor]
[4888]40    protected RunCollection(bool deserializing)
41      : base(deserializing) {
42      updateOfRunsInProgress = false;
43    }
[4722]44    protected RunCollection(RunCollection original, Cloner cloner)
45      : base(original, cloner) {
[4888]46      updateOfRunsInProgress = false;
[8962]47      optimizerName = original.optimizerName;
[8738]48
[4722]49      resultNames = new List<string>(original.resultNames);
50      parameterNames = new List<string>(original.parameterNames);
51      dataTypes = new Dictionary<string, HashSet<Type>>();
52      foreach (string s in original.dataTypes.Keys)
53        dataTypes[s] = new HashSet<Type>(original.dataTypes[s]);
54
55      constraints = new RunCollectionConstraintCollection(original.constraints.Select(x => cloner.Clone(x)));
[6693]56      modifiers = new CheckedItemList<IRunCollectionModifier>(original.modifiers.Select(cloner.Clone));
[4722]57      foreach (IRunCollectionConstraint constraint in constraints)
58        constraint.ConstrainedValue = this;
59      RegisterConstraintsEvents();
60      RegisterConstraintEvents(constraints);
61
62      UpdateFiltering(true);
63    }
[3329]64    public RunCollection() : base() { Initialize(); }
65    public RunCollection(int capacity) : base(capacity) { Initialize(); }
66    public RunCollection(IEnumerable<IRun> collection) : base(collection) { Initialize(); this.OnItemsAdded(collection); }
[3447]67    private void Initialize() {
[4888]68      updateOfRunsInProgress = false;
[3447]69      parameterNames = new List<string>();
70      resultNames = new List<string>();
[3614]71      dataTypes = new Dictionary<string, HashSet<Type>>();
72      constraints = new RunCollectionConstraintCollection();
[6693]73      modifiers = new CheckedItemList<IRunCollectionModifier>();
[4164]74      RegisterConstraintsEvents();
[3447]75    }
[4164]76
[3625]77    [Storable]
[3614]78    private Dictionary<string, HashSet<Type>> dataTypes;
79    public IEnumerable<Type> GetDataType(string columnName) {
80      if (!dataTypes.ContainsKey(columnName))
81        return new Type[0];
82      return dataTypes[columnName];
83    }
[4164]84
85    [Storable]
[3614]86    private RunCollectionConstraintCollection constraints;
87    public RunCollectionConstraintCollection Constraints {
[3625]88      get { return constraints; }
[3614]89    }
[3329]90
[6693]91    [Storable]
92    private CheckedItemList<IRunCollectionModifier> modifiers;
93    public CheckedItemList<IRunCollectionModifier> Modifiers {
94      get { return modifiers; }
95    }
96
97
[4888]98    private bool updateOfRunsInProgress;
99    public bool UpdateOfRunsInProgress {
100      get { return updateOfRunsInProgress; }
101      set {
102        if (updateOfRunsInProgress != value) {
103          updateOfRunsInProgress = value;
104          OnUpdateOfRunsInProgressChanged();
105        }
106      }
107    }
108
[8962]109    private string optimizerName = string.Empty;
[8738]110    [Storable]
[8962]111    public string OptimizerName {
112      get { return optimizerName; }
[8738]113      set {
[8962]114        if (value != optimizerName && !string.IsNullOrEmpty(value)) {
115          optimizerName = value;
116          OnOptimizerNameChanged();
[8738]117        }
118      }
119    }
120
[8967]121    // BackwardsCompatibility3.3
122    #region Backwards compatible code, remove with 3.4
[8962]123    [Storable(AllowOneWay = true)]
124    private string AlgorithmName {
125      set { optimizerName = value; }
126    }
[8967]127    #endregion
[8962]128
[4888]129    [StorableHook(HookType.AfterDeserialization)]
130    private void AfterDeserialization() {
131      if (constraints == null) constraints = new RunCollectionConstraintCollection();
[6693]132      if (modifiers == null) modifiers = new CheckedItemList<IRunCollectionModifier>();
[4888]133      RegisterConstraintsEvents();
134      RegisterConstraintEvents(constraints);
135      UpdateFiltering(true);
136    }
137
138    public override IDeepCloneable Clone(Cloner cloner) {
139      return new RunCollection(this, cloner);
140    }
141
142    public event EventHandler UpdateOfRunsInProgressChanged;
143    protected virtual void OnUpdateOfRunsInProgressChanged() {
144      var handler = UpdateOfRunsInProgressChanged;
145      if (handler != null) handler(this, EventArgs.Empty);
146    }
147
[8962]148    public event EventHandler OptimizerNameChanged;
149    protected virtual void OnOptimizerNameChanged() {
150      var handler = OptimizerNameChanged;
[8738]151      if (handler != null) handler(this, EventArgs.Empty);
152    }
153
[3329]154    protected override void OnCollectionReset(IEnumerable<IRun> items, IEnumerable<IRun> oldItems) {
155      parameterNames.Clear();
156      resultNames.Clear();
[7798]157      dataTypes.Clear();
[3329]158      foreach (IRun run in items) {
159        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
160          AddParameter(parameter.Key, parameter.Value);
161        foreach (KeyValuePair<string, IItem> result in run.Results)
162          AddResult(result.Key, result.Value);
[11344]163        run.PropertyChanged += RunOnPropertyChanged;
164        RegisterRunParametersEvents(run);
165        RegisterRunResultsEvents(run);
[3329]166      }
[11344]167      foreach (IRun run in oldItems) {
168        run.PropertyChanged -= RunOnPropertyChanged;
169        DeregisterRunParametersEvents(run);
170        DeregisterRunResultsEvents(run);
171      }
[4200]172      columnNameCache = null;
[5150]173      OnColumnsChanged();
[3329]174      OnColumnNamesChanged();
[4200]175      rowNamesCache = null;
[4518]176      base.OnCollectionReset(items, oldItems);
[5150]177      OnRowsChanged();
[3329]178      OnRowNamesChanged();
[4518]179      OnReset();
180      UpdateFiltering(false);
[3329]181    }
182    protected override void OnItemsAdded(IEnumerable<IRun> items) {
[5150]183      bool columnsChanged = false;
[3329]184      foreach (IRun run in items) {
185        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
[5150]186          columnsChanged |= AddParameter(parameter.Key, parameter.Value);
[3329]187        foreach (KeyValuePair<string, IItem> result in run.Results)
[5150]188          columnsChanged |= AddResult(result.Key, result.Value);
[11344]189        run.PropertyChanged += RunOnPropertyChanged;
190        RegisterRunParametersEvents(run);
191        RegisterRunResultsEvents(run);
[3329]192      }
[5150]193      if (columnsChanged) columnNameCache = null;
[4200]194      rowNamesCache = null;
[4518]195      base.OnItemsAdded(items);
[4707]196      OnReset();
[5150]197      OnRowsChanged();
[3329]198      OnRowNamesChanged();
[5150]199      if (columnsChanged) {
200        OnColumnsChanged();
201        OnColumnNamesChanged();
202      }
[4518]203      UpdateFiltering(false);
[3329]204    }
205    protected override void OnItemsRemoved(IEnumerable<IRun> items) {
[5150]206      bool columnsChanged = false;
[3329]207      foreach (IRun run in items) {
208        foreach (string parameterName in run.Parameters.Keys)
[5150]209          columnsChanged |= RemoveParameterName(parameterName);
[3329]210        foreach (string resultName in run.Results.Keys)
[5150]211          columnsChanged |= RemoveResultName(resultName);
[11344]212        run.PropertyChanged -= RunOnPropertyChanged;
213        DeregisterRunParametersEvents(run);
214        DeregisterRunResultsEvents(run);
[3329]215      }
[5150]216      if (columnsChanged) columnNameCache = null;
[4200]217      rowNamesCache = null;
[4518]218      base.OnItemsRemoved(items);
[4707]219      OnReset();
[5152]220      OnRowsChanged();
[3329]221      OnRowNamesChanged();
[5150]222      if (columnsChanged) {
223        OnColumnsChanged();
224        OnColumnNamesChanged();
225      }
[3329]226    }
227
[11344]228    private void RunOnPropertyChanged(object sender, PropertyChangedEventArgs e) {
229      if (e.PropertyName == "Parameters") {
230        RegisterRunParametersEvents((IRun)sender);
231      } else if (e.PropertyName == "Results") {
232        RegisterRunResultsEvents((IRun)sender);
233      }
234    }
235
236    private void RegisterRunParametersEvents(IRun run) {
237      IObservableDictionary<string, IItem> dict = run.Parameters;
238      dict.ItemsAdded += RunOnParameterChanged;
[11345]239      dict.ItemsRemoved += RunOnParameterRemoved;
[11344]240      dict.ItemsReplaced += RunOnParameterChanged;
241      dict.CollectionReset += RunOnParameterChanged;
242    }
243
244    private void RegisterRunResultsEvents(IRun run) {
245      IObservableDictionary<string, IItem> dict = run.Results;
246      dict.ItemsAdded += RunOnResultChanged;
[11345]247      dict.ItemsRemoved += RunOnResultRemoved;
[11344]248      dict.ItemsReplaced += RunOnResultChanged;
249      dict.CollectionReset += RunOnResultChanged;
250    }
251
252    private void DeregisterRunParametersEvents(IRun run) {
253      IObservableDictionary<string, IItem> dict = run.Parameters;
254      dict.ItemsAdded -= RunOnParameterChanged;
[11345]255      dict.ItemsRemoved -= RunOnParameterRemoved;
[11344]256      dict.ItemsReplaced -= RunOnParameterChanged;
257      dict.CollectionReset -= RunOnParameterChanged;
258    }
259
260    private void DeregisterRunResultsEvents(IRun run) {
261      IObservableDictionary<string, IItem> dict = run.Results;
262      dict.ItemsAdded -= RunOnResultChanged;
[11345]263      dict.ItemsRemoved -= RunOnResultRemoved;
[11344]264      dict.ItemsReplaced -= RunOnResultChanged;
265      dict.CollectionReset -= RunOnResultChanged;
266    }
267
268    private void RunOnParameterChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
269      bool columnsChanged = false;
270      foreach (var param in e.Items)
271        columnsChanged |= AddParameter(param.Key, param.Value);
272      foreach (var param in e.OldItems)
273        columnsChanged |= RemoveParameterName(param.Key);
274      if (columnsChanged) columnNameCache = null;
275      OnReset();
276      if (columnsChanged) {
277        OnColumnsChanged();
278        OnColumnNamesChanged();
279      }
280    }
281
[11345]282    private void RunOnParameterRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
283      bool columnsChanged = false;
284      foreach (var param in e.Items)
285        columnsChanged |= RemoveParameterName(param.Key);
286      if (columnsChanged) columnNameCache = null;
287      OnReset();
288      if (columnsChanged) {
289        OnColumnsChanged();
290        OnColumnNamesChanged();
291      }
292    }
293
[11344]294    private void RunOnResultChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
295      bool columnsChanged = false;
296      foreach (var result in e.Items)
297        columnsChanged |= AddResult(result.Key, result.Value);
298      foreach (var result in e.OldItems)
299        columnsChanged |= RemoveResultName(result.Key);
300      if (columnsChanged) columnNameCache = null;
301      OnReset();
302      if (columnsChanged) {
303        OnColumnsChanged();
304        OnColumnNamesChanged();
305      }
306    }
307
[11345]308    private void RunOnResultRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
309      bool columnsChanged = false;
310      foreach (var result in e.Items)
311        columnsChanged |= RemoveResultName(result.Key);
312      if (columnsChanged) columnNameCache = null;
313      OnReset();
314      if (columnsChanged) {
315        OnColumnsChanged();
316        OnColumnNamesChanged();
317      }
318    }
319
[3329]320    private bool AddParameter(string name, IItem value) {
321      if (value == null)
322        return false;
[3441]323      if (!parameterNames.Contains(name)) {
[3329]324        parameterNames.Add(name);
[3614]325        dataTypes[name] = new HashSet<Type>();
326        dataTypes[name].Add(value.GetType());
[3329]327        return true;
328      }
[3614]329      dataTypes[name].Add(value.GetType());
[3329]330      return false;
331    }
332    private bool AddResult(string name, IItem value) {
333      if (value == null)
334        return false;
[3441]335      if (!resultNames.Contains(name)) {
[3329]336        resultNames.Add(name);
[3614]337        dataTypes[name] = new HashSet<Type>();
338        dataTypes[name].Add(value.GetType());
[3329]339        return true;
340      }
[3614]341      dataTypes[name].Add(value.GetType());
[3329]342      return false;
343    }
344    private bool RemoveParameterName(string name) {
345      if (!list.Any(x => x.Parameters.ContainsKey(name))) {
346        parameterNames.Remove(name);
347        return true;
348      }
349      return false;
350    }
351    private bool RemoveResultName(string name) {
352      if (!list.Any(x => x.Results.ContainsKey(name))) {
353        resultNames.Remove(name);
354        return true;
355      }
356      return false;
357    }
358
[3447]359    public IItem GetValue(int rowIndex, int columnIndex) {
360      IRun run = this.list[rowIndex];
[3492]361      return GetValue(run, columnIndex);
362    }
363
364    public IItem GetValue(IRun run, int columnIndex) {
[3717]365      string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
366      return GetValue(run, name);
367    }
368
369    public IItem GetValue(IRun run, string columnName) {
[3447]370      IItem value = null;
[3767]371      if (run.Parameters.ContainsKey(columnName))
372        value = run.Parameters[columnName];
373      else if (run.Results.ContainsKey(columnName))
374        value = run.Results[columnName];
[3447]375      return value;
376    }
377
[3329]378    #region IStringConvertibleMatrix Members
[3347]379    [Storable]
[3329]380    private List<string> parameterNames;
[3492]381    public IEnumerable<string> ParameterNames {
382      get { return this.parameterNames; }
383    }
[3347]384    [Storable]
[3329]385    private List<string> resultNames;
[3492]386    public IEnumerable<string> ResultNames {
387      get { return this.resultNames; }
388    }
[3447]389    int IStringConvertibleMatrix.Rows {
[3329]390      get { return this.Count; }
[3447]391      set { throw new NotSupportedException(); }
[3329]392    }
[3447]393    int IStringConvertibleMatrix.Columns {
[3329]394      get { return parameterNames.Count + resultNames.Count; }
395      set { throw new NotSupportedException(); }
396    }
[4200]397    private List<string> columnNameCache;
[3447]398    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
[3329]399      get {
[4200]400        if (columnNameCache == null) {
401          columnNameCache = new List<string>(parameterNames);
402          columnNameCache.AddRange(resultNames);
403          columnNameCache.Sort();
404        }
405        return columnNameCache;
[3329]406      }
407      set { throw new NotSupportedException(); }
408    }
[4200]409    private List<string> rowNamesCache;
[3447]410    IEnumerable<string> IStringConvertibleMatrix.RowNames {
[4200]411      get {
412        if (rowNamesCache == null)
413          rowNamesCache = list.Select(x => x.Name).ToList();
414        return rowNamesCache;
415      }
[3329]416      set { throw new NotSupportedException(); }
417    }
[3447]418    bool IStringConvertibleMatrix.SortableView {
[3329]419      get { return true; }
420      set { throw new NotSupportedException(); }
421    }
[3447]422    bool IStringConvertibleMatrix.ReadOnly {
423      get { return true; }
[3430]424    }
[3329]425
[3447]426    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
427      IItem value = GetValue(rowIndex, columnIndex);
428      if (value == null)
429        return string.Empty;
430      return value.ToString();
[3329]431    }
432
433    public event EventHandler<EventArgs<int, int>> ItemChanged;
434    protected virtual void OnItemChanged(int rowIndex, int columnIndex) {
[4722]435      EventHandler<EventArgs<int, int>> handler = ItemChanged;
436      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
[3329]437      OnToStringChanged();
438    }
439    public event EventHandler Reset;
440    protected virtual void OnReset() {
[4722]441      EventHandler handler = Reset;
442      if (handler != null) handler(this, EventArgs.Empty);
[3329]443      OnToStringChanged();
444    }
[5150]445    public event EventHandler ColumnsChanged;
446    protected virtual void OnColumnsChanged() {
447      var handler = ColumnsChanged;
448      if (handler != null) handler(this, EventArgs.Empty);
449    }
450    public event EventHandler RowsChanged;
451    protected virtual void OnRowsChanged() {
452      var handler = RowsChanged;
453      if (handler != null) handler(this, EventArgs.Empty);
454    }
[3329]455    public event EventHandler ColumnNamesChanged;
456    protected virtual void OnColumnNamesChanged() {
457      EventHandler handler = ColumnNamesChanged;
[4722]458      if (handler != null) handler(this, EventArgs.Empty);
[3329]459    }
460    public event EventHandler RowNamesChanged;
461    protected virtual void OnRowNamesChanged() {
462      EventHandler handler = RowNamesChanged;
[4722]463      if (handler != null) handler(this, EventArgs.Empty);
[3329]464    }
465    public event EventHandler SortableViewChanged;
[3333]466    protected virtual void OnSortableViewChanged() {
467      EventHandler handler = SortableViewChanged;
[4722]468      if (handler != null) handler(this, EventArgs.Empty);
[3333]469    }
470
[3329]471    public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); }
472    public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); }
473    #endregion
[3614]474
[4888]475    #region Filtering
[3632]476    private void UpdateFiltering(bool reset) {
[4888]477      UpdateOfRunsInProgress = true;
[3632]478      if (reset)
479        list.ForEach(r => r.Visible = true);
[3614]480      foreach (IRunCollectionConstraint constraint in this.constraints)
481        constraint.Check();
[4888]482      UpdateOfRunsInProgress = false;
[3614]483    }
484
[4164]485    private void RegisterConstraintsEvents() {
486      constraints.ItemsAdded += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsAdded);
487      constraints.ItemsRemoved += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsRemoved);
488      constraints.CollectionReset += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_CollectionReset);
489    }
490
[3614]491    protected virtual void RegisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
492      foreach (IRunCollectionConstraint constraint in constraints) {
493        constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged);
494        constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged);
495        constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged);
496        constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged);
497      }
498    }
499    protected virtual void DeregisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
500      foreach (IRunCollectionConstraint constraint in constraints) {
501        constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged);
502        constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged);
503        constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged);
504        constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged);
505      }
506    }
507
508    protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
509      DeregisterConstraintEvents(e.OldItems);
510      RegisterConstraintEvents(e.Items);
[3632]511      this.UpdateFiltering(true);
[3614]512    }
513    protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
514      RegisterConstraintEvents(e.Items);
515      foreach (IRunCollectionConstraint constraint in e.Items)
516        constraint.ConstrainedValue = this;
[3632]517      this.UpdateFiltering(false);
[3614]518    }
519    protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
520      DeregisterConstraintEvents(e.Items);
[3632]521      this.UpdateFiltering(true);
[3614]522    }
523    protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) {
[3632]524      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
525      this.UpdateFiltering(!constraint.Active);
[3614]526    }
527    protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) {
528      //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method
529    }
530    protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) {
[3632]531      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
532      if (constraint.Active)
533        this.UpdateFiltering(true);
[3614]534    }
535    protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) {
[3632]536      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
537      if (constraint.Active)
538        this.UpdateFiltering(true);
[3614]539    }
540    #endregion
[6693]541
542    #region Modification
543    public void Modify() {
544      UpdateOfRunsInProgress = true;
545      var runs = this.ToList();
546      var selectedRuns = runs.Where(r => r.Visible).ToList();
547      int nSelected = selectedRuns.Count;
548      if (nSelected > 0) {
549        foreach (var modifier in Modifiers.CheckedItems)
550          modifier.Value.Modify(selectedRuns);
551        if (nSelected != selectedRuns.Count || HaveDifferentOrder(selectedRuns, runs.Where(r => r.Visible))) {
552          Clear();
553          AddRange(ReplaceVisibleRuns(runs, selectedRuns));
554        } else if (runs.Count > 0) {
555          OnCollectionReset(this, runs);
556        }
557      }
558      UpdateOfRunsInProgress = false;
559    }
560
561    private static IEnumerable<IRun> ReplaceVisibleRuns(IEnumerable<IRun> runs, IEnumerable<IRun> visibleRuns) {
562      var newRuns = new List<IRun>();
563      var runIt = runs.GetEnumerator();
564      var visibleRunIt = visibleRuns.GetEnumerator();
565      while (runIt.MoveNext()) {
566        if (runIt.Current != null && !runIt.Current.Visible)
567          newRuns.Add(runIt.Current);
568        else if (visibleRunIt.MoveNext())
569          newRuns.Add(visibleRunIt.Current);
570      }
571      while (visibleRunIt.MoveNext())
572        newRuns.Add(visibleRunIt.Current);
573      return newRuns;
574    }
575
576    private static bool HaveDifferentOrder(IEnumerable<IRun> l1, IEnumerable<IRun> l2) {
577      return l1.Zip(l2, (r1, r2) => r1 != r2).Any();
578    }
579    #endregion
[3260]580  }
581}
Note: See TracBrowser for help on using the repository browser.