Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs	(revision 15638)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs	(revision 16432)
@@ -19,7 +19,11 @@
  */
 #endregion
+
 using System;
+using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
+using HeuristicLab.Common;
 using HeuristicLab.Data;
 using HeuristicLab.MainForm;
@@ -29,5 +33,18 @@
   [Content(typeof(IClassificationSolution))]
   public partial class ClassificationSolutionVariableImpactsView : DataAnalysisSolutionEvaluationView {
-
+    #region Nested Types
+    private enum SortingCriteria {
+      ImpactValue,
+      Occurrence,
+      VariableName
+    }
+    #endregion
+
+    #region Fields
+    private Dictionary<string, double> rawVariableImpacts = new Dictionary<string, double>();
+    private Thread thread;
+    #endregion
+
+    #region Getter/Setter
     public new IClassificationSolution Content {
       get { return (IClassificationSolution)base.Content; }
@@ -36,14 +53,22 @@
       }
     }
-
+    #endregion
+
+    #region Ctor
     public ClassificationSolutionVariableImpactsView()
       : base() {
       InitializeComponent();
+
+      this.sortByComboBox.Items.AddRange(Enum.GetValues(typeof(SortingCriteria)).Cast<object>().ToArray());
+      this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
+
+      //Set the default values
       this.dataPartitionComboBox.SelectedIndex = 0;
       this.replacementComboBox.SelectedIndex = 0;
       this.factorVarReplComboBox.SelectedIndex = 0;
     }
-
-    #region events
+    #endregion
+
+    #region Events
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
@@ -71,46 +96,129 @@
         variableImactsArrayView.Content = null;
       } else {
-        UpdateVariableImpacts();
-      }
-    }
-
-    private void UpdateVariableImpacts() {
-      if (Content == null || replacementComboBox.SelectedIndex < 0
-        || factorVarReplComboBox.SelectedIndex < 0
-        || dataPartitionComboBox.SelectedIndex < 0) return;
+        UpdateVariableImpact();
+      }
+    }
+
+    private void ClassificationSolutionVariableImpactsView_VisibleChanged(object sender, EventArgs e) {
+      if (thread == null) { return; }
+
+      if (thread.IsAlive) { thread.Abort(); }
+      thread = null;
+    }
+
+
+    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateVariableImpact();
+    }
+
+    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateVariableImpact();
+    }
+
+    private void sortByComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      //Update the default ordering (asc,desc), but remove the eventHandler beforehand (otherwise the data would be ordered twice)
+      ascendingCheckBox.CheckedChanged -= ascendingCheckBox_CheckedChanged;
+      switch ((SortingCriteria)sortByComboBox.SelectedItem) {
+        case SortingCriteria.ImpactValue:
+          ascendingCheckBox.Checked = false;
+          break;
+        case SortingCriteria.Occurrence:
+          ascendingCheckBox.Checked = true;
+          break;
+        case SortingCriteria.VariableName:
+          ascendingCheckBox.Checked = true;
+          break;
+        default:
+          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
+      }
+      ascendingCheckBox.CheckedChanged += ascendingCheckBox_CheckedChanged;
+
+      UpdateDataOrdering();
+    }
+
+    private void ascendingCheckBox_CheckedChanged(object sender, EventArgs e) {
+      UpdateDataOrdering();
+    }
+
+    #endregion
+
+    #region Helper Methods   
+    private void UpdateVariableImpact() {
+      //Check if the selection is valid
+      if (Content == null) { return; }
+      if (replacementComboBox.SelectedIndex < 0) { return; }
+      if (dataPartitionComboBox.SelectedIndex < 0) { return; }
+      if (factorVarReplComboBox.SelectedIndex < 0) { return; }
+
+      //Prepare arguments
       var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
+      var replMethod = (ClassificationSolutionVariableImpactsCalculator.ReplacementMethodEnum)replacementComboBox.Items[replacementComboBox.SelectedIndex];
+      var factorReplMethod = (ClassificationSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
+      var dataPartition = (ClassificationSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
+
       variableImactsArrayView.Caption = Content.Name + " Variable Impacts";
-      var replMethod =
-         (ClassificationSolutionVariableImpactsCalculator.ReplacementMethodEnum)
-           replacementComboBox.Items[replacementComboBox.SelectedIndex];
-      var factorReplMethod =
-        (ClassificationSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)
-          factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
-      var dataPartition =
-        (ClassificationSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
+
+      mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
 
       Task.Factory.StartNew(() => {
-        try {
-          mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
-
-          var impacts = ClassificationSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
-          var impactArray = new DoubleArray(impacts.Select(i => i.Item2).ToArray());
-          impactArray.ElementNames = impacts.Select(i => i.Item1);
-          variableImactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
-        } finally {
-          mainForm.RemoveOperationProgressFromView(this);
-        }
-      });
-    }
-
-    #endregion
-
-    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateVariableImpacts();
-    }
-
-    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateVariableImpacts();
-    }
+        thread = Thread.CurrentThread;
+        //Remember the original ordering of the variables
+        var impacts = ClassificationSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
+        var problemData = Content.ProblemData;
+        var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
+        var originalVariableOrdering = problemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).Where(problemData.Dataset.VariableHasType<double>).ToList();
+
+        rawVariableImpacts.Clear();
+        originalVariableOrdering.ForEach(v => rawVariableImpacts.Add(v, impacts.First(vv => vv.Item1 == v).Item2));
+      }).ContinueWith((o) => {
+        UpdateDataOrdering();
+        mainForm.RemoveOperationProgressFromView(this);
+        thread = null;
+      }, TaskScheduler.FromCurrentSynchronizationContext());
+    }
+
+    /// <summary>
+    /// Updates the <see cref="variableImactsArrayView"/> according to the selected ordering <see cref="ascendingCheckBox"/> of the selected Column <see cref="sortByComboBox"/>
+    /// The default is "Descending" by "VariableImpact" (as in previous versions)
+    /// </summary>
+    private void UpdateDataOrdering() {
+      //Check if valid sortingCriteria is selected and data exists
+      if (sortByComboBox.SelectedIndex == -1) { return; }
+      if (rawVariableImpacts == null) { return; }
+      if (!rawVariableImpacts.Any()) { return; }
+
+      var selectedItem = (SortingCriteria)sortByComboBox.SelectedItem;
+      bool ascending = ascendingCheckBox.Checked;
+
+      IEnumerable<KeyValuePair<string, double>> orderedEntries = null;
+
+      //Sort accordingly
+      switch (selectedItem) {
+        case SortingCriteria.ImpactValue:
+          orderedEntries = rawVariableImpacts.OrderBy(v => v.Value);
+          break;
+        case SortingCriteria.Occurrence:
+          orderedEntries = rawVariableImpacts;
+          break;
+        case SortingCriteria.VariableName:
+          orderedEntries = rawVariableImpacts.OrderBy(v => v.Key, new NaturalStringComparer());
+          break;
+        default:
+          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
+      }
+
+      if (!ascending) { orderedEntries = orderedEntries.Reverse(); }
+
+      //Write the data back
+      var impactArray = new DoubleArray(orderedEntries.Select(i => i.Value).ToArray()) {
+        ElementNames = orderedEntries.Select(i => i.Key)
+      };
+
+      //Could be, if the View was closed
+      if (!variableImactsArrayView.IsDisposed) {
+        variableImactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
+      }
+    }
+    #endregion  
   }
 }
