Index: branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 15700)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 15701)
@@ -87,5 +87,6 @@
     private readonly BindingList<ProblemInstance> problems;
 
-    private bool suppressUpdates;
+    private bool updateInProgress;
+    private bool suppressContentEvents;
     private readonly IndexedDataTable<double> byCostDataTable;
     public IndexedDataTable<double> ByCostDataTable {
@@ -97,23 +98,25 @@
       invisibleTargetSeries = new List<Series>();
 
-      targetChart.CustomizeAllChartAreas();
-      targetChart.ChartAreas[0].CursorX.Interval = 1;
-      targetChart.SuppressExceptions = true;
-      byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of function values (relative to best-known).") {
-        VisualProperties = {
-          YAxisTitle = "Proportion of runs",
-          YAxisMinimumFixedValue = 0,
-          YAxisMinimumAuto = false,
-          YAxisMaximumFixedValue = 1,
-          YAxisMaximumAuto = false
-        }
-      };
-      byCostViewHost.Content = byCostDataTable;
-      suppressUpdates = true;
-      relativeOrAbsoluteComboBox.SelectedItem = targetsAreRelative ? "relative" : "absolute";
-      problems = new BindingList<ProblemInstance>();
-      problemComboBox.DataSource = new BindingSource() { DataSource = problems };
-      problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
-      suppressUpdates = false;
+      try {
+        updateInProgress = true;
+        targetChart.CustomizeAllChartAreas();
+        targetChart.ChartAreas[0].CursorX.Interval = 1;
+        targetChart.SuppressExceptions = true;
+        byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of function values (relative to best-known).") {
+          VisualProperties = {
+            YAxisTitle = "Proportion of runs",
+            YAxisMinimumFixedValue = 0,
+            YAxisMinimumAuto = false,
+            YAxisMaximumFixedValue = 1,
+            YAxisMaximumAuto = false
+          }
+        };
+        byCostViewHost.Content = byCostDataTable;
+
+        relativeOrAbsoluteComboBox.SelectedItem = targetsAreRelative ? "relative" : "absolute";
+        problems = new BindingList<ProblemInstance>();
+        problemComboBox.DataSource = new BindingSource() { DataSource = problems };
+        problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
+      } finally { updateInProgress = false; }
     }
 
@@ -137,38 +140,45 @@
 
     private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      if (suppressUpdates) return;
+      foreach (var run in e.Items) RegisterRunEvents(run);
+      if (suppressContentEvents) return;
       if (InvokeRequired) {
         Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded), sender, e);
         return;
       }
-      UpdateGroupAndProblemComboBox();
-      UpdateDataTableComboBox();
-      GroupRuns();
-      foreach (var run in e.Items)
-        RegisterRunEvents(run);
+      try {
+        updateInProgress = true;
+        UpdateGroupAndProblemComboBox();
+        UpdateDataTableComboBox();
+        GroupRuns();
+      } finally { updateInProgress = false; }
     }
     private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      if (suppressUpdates) return;
+      foreach (var run in e.Items) DeregisterRunEvents(run);
+      if (suppressContentEvents) return;
       if (InvokeRequired) {
         Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved), sender, e);
         return;
       }
-      UpdateGroupAndProblemComboBox();
-      UpdateDataTableComboBox();
-      GroupRuns();
-      foreach (var run in e.Items)
-        DeregisterRunEvents(run);
+      try {
+        updateInProgress = true;
+        UpdateGroupAndProblemComboBox();
+        UpdateDataTableComboBox();
+        GroupRuns();
+      } finally { updateInProgress = false; }
     }
     private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      if (suppressUpdates) return;
+      foreach (var run in e.OldItems) DeregisterRunEvents(run);
+      foreach (var run in e.Items) RegisterRunEvents(run);
+      if (suppressContentEvents) return;
       if (InvokeRequired) {
         Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset), sender, e);
         return;
       }
-      UpdateGroupAndProblemComboBox();
-      UpdateDataTableComboBox();
-      GroupRuns();
-      foreach (var run in e.OldItems)
-        DeregisterRunEvents(run);
+      try {
+        updateInProgress = true;
+        UpdateGroupAndProblemComboBox();
+        UpdateDataTableComboBox();
+        GroupRuns();
+      } finally { updateInProgress = false; }
     }
     private void Content_AlgorithmNameChanged(object sender, EventArgs e) {
@@ -182,9 +192,12 @@
         return;
       }
-      suppressUpdates = Content.UpdateOfRunsInProgress;
-      if (!suppressUpdates) {
-        UpdateDataTableComboBox();
-        UpdateGroupAndProblemComboBox();
-        UpdateRuns();
+      suppressContentEvents = Content.UpdateOfRunsInProgress;
+      if (!suppressContentEvents) {
+        try {
+          updateInProgress = true;
+          UpdateGroupAndProblemComboBox();
+          UpdateDataTableComboBox();
+          GroupRuns();
+        } finally { updateInProgress = false; }
       }
     }
@@ -197,10 +210,14 @@
     }
     private void run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
-      if (suppressUpdates) return;
+      if (suppressContentEvents) return;
       if (InvokeRequired) {
         Invoke((Action<object, PropertyChangedEventArgs>)run_PropertyChanged, sender, e);
       } else {
-        if (e.PropertyName == "Visible")
-          UpdateRuns();
+        if (e.PropertyName == "Visible") {
+          try {
+            updateInProgress = true;
+            UpdateRuns();
+          } finally { updateInProgress = false; }
+        }
       }
     }
@@ -219,7 +236,10 @@
       UpdateCaption();
       if (Content != null) {
-        UpdateGroupAndProblemComboBox();
-        UpdateDataTableComboBox();
-        GroupRuns();
+        try {
+          updateInProgress = true;
+          UpdateGroupAndProblemComboBox();
+          UpdateDataTableComboBox();
+          UpdateRuns();
+        } finally { updateInProgress = false; }
       }
     }
@@ -239,30 +259,14 @@
       }
 
-      var table = (string)dataTableComboBox.SelectedItem;
-      var problemDict = CalculateBestTargetPerProblemInstance(table);
-
-      var problemTypesDifferent = problemDict.Keys.Select(x => x.ProblemType).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
-      var problemNamesDifferent = problemDict.Keys.Select(x => x.ProblemName).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
-      var evaluatorDifferent = problemDict.Keys.Select(x => x.Evaluator).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
-      var maximizationDifferent = problemDict.Keys.Select(x => x.Maximization).Distinct().Count() > 1;
-      var allEqual = !problemTypesDifferent && !problemNamesDifferent && !evaluatorDifferent && !maximizationDifferent;
-
       var selectedProblemItem = (ProblemInstance)problemComboBox.SelectedItem;
-      problemComboBox.DataSource = null;
-      problemComboBox.Items.Clear();
-      problems.Clear();
-      problems.Add(ProblemInstance.MatchAll);
-      problemComboBox.DataSource = new BindingSource() { DataSource = problems };
-      problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
-      if (problems[0].Equals(selectedProblemItem)) problemComboBox.SelectedItem = problems[0];
-      foreach (var p in problemDict.ToList()) {
-        p.Key.BestKnownQuality = p.Value;
-        p.Key.DisplayProblemType = problemTypesDifferent;
-        p.Key.DisplayProblemName = problemNamesDifferent || allEqual;
-        p.Key.DisplayEvaluator = evaluatorDifferent;
-        p.Key.DisplayMaximization = maximizationDifferent;
-        problems.Add(p.Key);
-        if (p.Key.Equals(selectedProblemItem)) problemComboBox.SelectedItem = p.Key;
-      }
+      
+      UpdateProblemInstances();
+      
+      foreach (var p in problems) {
+        if (p.Equals(selectedProblemItem))
+          problemComboBox.SelectedItem = p;
+      }
+
+      if (selectedProblemItem == null && problems.Count > 1) problemComboBox.SelectedItem = problems[1];
 
       SetEnabledStateOfControls();
@@ -284,4 +288,6 @@
         dataTableComboBox.SelectedItem = dataTableComboBox.Items[0];
       }
+
+      UpdateProblemInstances();
     }
 
@@ -326,4 +332,30 @@
         groups.Add(new AlgorithmInstance(alg.Key, trials));
       }
+    }
+
+    private void UpdateProblemInstances() {
+      try {
+        problems.Clear();
+        var table = (string)dataTableComboBox.SelectedItem;
+        if (string.IsNullOrEmpty(table)) return;
+
+        var problemDict = CalculateBestTargetPerProblemInstance(table);
+
+        var problemTypesDifferent = problemDict.Keys.Select(x => x.ProblemType).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var problemNamesDifferent = problemDict.Keys.Select(x => x.ProblemName).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var evaluatorDifferent = problemDict.Keys.Select(x => x.Evaluator).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var maximizationDifferent = problemDict.Keys.Select(x => x.Maximization).Distinct().Count() > 1;
+        var allEqual = !problemTypesDifferent && !problemNamesDifferent && !evaluatorDifferent && !maximizationDifferent;
+
+        problems.Add(ProblemInstance.MatchAll);
+        foreach (var p in problemDict.ToList()) {
+          p.Key.BestKnownQuality = p.Value;
+          p.Key.DisplayProblemType = problemTypesDifferent;
+          p.Key.DisplayProblemName = problemNamesDifferent || allEqual;
+          p.Key.DisplayEvaluator = evaluatorDifferent;
+          p.Key.DisplayMaximization = maximizationDifferent;
+          problems.Add(p.Key);
+        }
+      } finally { ((BindingSource)problemComboBox.DataSource).ResetBindings(false); }
     }
 
@@ -570,4 +602,5 @@
     private IEnumerable<double> GetAbsoluteTargets(ProblemInstance pInstance) {
       if (!targetsAreRelative) return targets;
+
       var maximization = pInstance.IsMaximization();
       var bestKnown = pInstance.BestKnownQuality;
@@ -586,5 +619,5 @@
 
     private double[] GetAbsoluteTargetsWorstToBest(ProblemInstance pInstance) {
-      if (double.IsNaN(pInstance.BestKnownQuality)) throw new ArgumentException("Problem instance does not have a defined best-known quality.");
+      if (targetsAreRelative && double.IsNaN(pInstance.BestKnownQuality)) throw new ArgumentException("Problem instance does not have a defined best-known quality.");
       var absTargets = GetAbsoluteTargets(pInstance);
       return (pInstance.IsMaximization()
@@ -719,9 +752,8 @@
 
     private void GenerateDefaultBudgets(string table) {
-      var runs = Content.Where(x => x.Results.ContainsKey(table) && x.Results[table] is IndexedDataTable<double>
-                                    && ((IndexedDataTable<double>)x.Results[table]).Rows.Count > 0
-                                    && ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values
-                                      .Any(y => !double.IsNaN(y.Item2)))
-                        .Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First())
+      var runs = Content.Where(x => x.Results.ContainsKey(table) && x.Results[table] is IndexedDataTable<double>)
+                        .Select(x => (IndexedDataTable<double>)x.Results[table])
+                        .Where(x => x.Rows.Count > 0)
+                        .Select(x => x.Rows.First())
                         .ToList();
       if (runs.Count == 0) {
@@ -733,6 +765,6 @@
       }
 
-      var min = runs.Select(x => x.Values.Where(y => !double.IsNaN(y.Item2)).Select(y => y.Item1).Min()).Min();
-      var max = runs.Select(x => x.Values.Where(y => !double.IsNaN(y.Item2)).Select(y => y.Item1).Max()).Max();
+      var min = runs.Select(x => x.Values.Select(y => y.Item1).Min()).Min();
+      var max = runs.Select(x => x.Values.Select(y => y.Item1).Max()).Max();
       var points = 3;
       budgets = Enumerable.Range(1, points).Select(x => min + (x / (double)points) * (max - min)).ToArray();
@@ -770,27 +802,36 @@
       if (InvokeRequired) Invoke((Action)SynchronizeTargetTextBox);
       else {
-        suppressTargetsEvents = true;
-        try {
-          if (targetsAreRelative)
-            targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
-          else targetsTextBox.Text = string.Join(" ; ", targets);
-        } finally { suppressTargetsEvents = false; }
+        if (targetsAreRelative)
+          targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
+        else targetsTextBox.Text = string.Join(" ; ", targets);
       }
     }
 
     private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateRuns();
-      SetEnabledStateOfControls();
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
     }
     private void problemComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateRuns();
-      SetEnabledStateOfControls();
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
     }
     private void dataTableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      if (dataTableComboBox.SelectedIndex >= 0)
-        GenerateDefaultBudgets((string)dataTableComboBox.SelectedItem);
-      UpdateBestKnownQualities();
-      UpdateRuns();
-      SetEnabledStateOfControls();
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        if (dataTableComboBox.SelectedIndex >= 0)
+          GenerateDefaultBudgets((string)dataTableComboBox.SelectedItem);
+        UpdateBestKnownQualities();
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
     }
 
@@ -805,63 +846,75 @@
 
     #region Event handlers for target analysis
-    private bool suppressTargetsEvents;
     private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
-      if (suppressTargetsEvents) return;
-      var targetStrings = targetsTextBox.Text.Split(new[] { '%', ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
-      var targetList = new List<decimal>();
-      foreach (var ts in targetStrings) {
-        decimal t;
-        if (!decimal.TryParse(ts, out t)) {
-          errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        var targetStrings = targetsTextBox.Text.Split(new[] { '%', ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
+        var targetList = new List<decimal>();
+        foreach (var ts in targetStrings) {
+          decimal t;
+          if (!decimal.TryParse(ts, out t)) {
+            errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
+            e.Cancel = true;
+            return;
+          }
+          if (targetsAreRelative)
+            targetList.Add(t / 100);
+          else targetList.Add(t);
+        }
+        if (targetList.Count == 0) {
+          errorProvider.SetError(targetsTextBox, "Give at least one target value!");
           e.Cancel = true;
           return;
         }
-        if (targetsAreRelative)
-          targetList.Add(t / 100);
-        else targetList.Add(t);
-      }
-      if (targetList.Count == 0) {
-        errorProvider.SetError(targetsTextBox, "Give at least one target value!");
-        e.Cancel = true;
-        return;
-      }
-      e.Cancel = false;
-      errorProvider.SetError(targetsTextBox, null);
-      targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
-
-      SynchronizeTargetTextBox();
-      UpdateResultsByTarget();
-      SetEnabledStateOfControls();
+        e.Cancel = false;
+        errorProvider.SetError(targetsTextBox, null);
+        targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
+
+        SynchronizeTargetTextBox();
+        UpdateResultsByTarget();
+        SetEnabledStateOfControls();
+
+      } finally { updateInProgress = false; }
     }
 
     private void aggregateTargetsCheckBox_CheckedChanged(object sender, EventArgs e) {
-      SuspendRepaint();
+      if (updateInProgress) return;
       try {
-        UpdateResultsByTarget();
-      } finally { ResumeRepaint(true); }
-    }
-
-    private void relativeOrAbsoluteComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      if (suppressUpdates) return;
-      var pd = (ProblemInstance)problemComboBox.SelectedItem;
-      if (!double.IsNaN(pd.BestKnownQuality)) {
-        var max = pd.IsMaximization();
-        if (targetsAreRelative) targets = GetAbsoluteTargets(pd).ToArray();
-        else {
-          // Rounding to 5 digits since it's certainly appropriate for this application
-          if (pd.BestKnownQuality > 0) {
-            targets = targets.Select(x => Math.Round(max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
-          } else if (pd.BestKnownQuality < 0) {
-            targets = targets.Select(x => Math.Round(!max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
-          }
-        }
-      }
-      targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
-      SynchronizeTargetTextBox();
-
-      try {
+        updateInProgress = true;
         SuspendRepaint();
         UpdateResultsByTarget();
-      } finally { ResumeRepaint(true); }
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
+    }
+
+    private void relativeOrAbsoluteComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        var pd = (ProblemInstance)problemComboBox.SelectedItem;
+        if (!double.IsNaN(pd.BestKnownQuality)) {
+          var max = pd.IsMaximization();
+          if (targetsAreRelative) targets = GetAbsoluteTargets(pd).ToArray();
+          else {
+            // Rounding to 5 digits since it's certainly appropriate for this application
+            if (pd.BestKnownQuality > 0) {
+              targets = targets.Select(x => Math.Round(max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
+            } else if (pd.BestKnownQuality < 0) {
+              targets = targets.Select(x => Math.Round(!max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
+            }
+          }
+        }
+        targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
+        SynchronizeTargetTextBox();
+        
+        SuspendRepaint();
+        UpdateResultsByTarget();
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
     }
 
@@ -883,7 +936,10 @@
               : dialog.Values.Select(x => (double)x).ToArray();
 
-            SynchronizeTargetTextBox();
-            UpdateResultsByTarget();
-            SetEnabledStateOfControls();
+            try {
+              updateInProgress = true;
+              SynchronizeTargetTextBox();
+              UpdateResultsByTarget();
+              SetEnabledStateOfControls();
+            } finally { updateInProgress = false; }
           }
         }
@@ -896,10 +952,10 @@
       
       foreach (var run in Content) {
-        if (!run.Results.ContainsKey(table)) continue;
+        if (!run.Results.ContainsKey(table) || !(run.Results[table] is IndexedDataTable<double>)) continue;
         var resultsTable = (IndexedDataTable<double>)run.Results[table];
         var values = resultsTable.Rows.First().Values;
         var pd = new ProblemInstance(run);
         pd = problems.Single(x => x.Equals(pd));
-        if (double.IsNaN(pd.BestKnownQuality)) continue;
+        if (targetsAreRelative && double.IsNaN(pd.BestKnownQuality)) continue;
 
         var max = pd.IsMaximization();
@@ -923,16 +979,24 @@
 
     private void markerCheckBox_CheckedChanged(object sender, EventArgs e) {
-      SuspendRepaint();
       try {
+        updateInProgress = true;
+        SuspendRepaint();
         UpdateResultsByTarget();
-      } finally { ResumeRepaint(true); }
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
     }
 
     private void showLabelsCheckBox_CheckedChanged(object sender, EventArgs e) {
       showLabelsInTargetChart = showLabelsCheckBox.Checked;
-      SuspendRepaint();
       try {
+        updateInProgress = true;
+        SuspendRepaint();
         UpdateResultsByTarget();
-      } finally { ResumeRepaint(true); }
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
     }
     #endregion
@@ -1186,4 +1250,5 @@
     }
 
+    #region Helper classes
     private class AlgorithmInstance : INotifyPropertyChanged {
       private string name;
@@ -1526,4 +1591,5 @@
       }
     }
+    #endregion
   }
 }
