Index: /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/DoubleMatrix.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/DoubleMatrix.cs	(revision 17689)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/DoubleMatrix.cs	(revision 17690)
@@ -42,4 +42,23 @@
     public DoubleMatrix(double[,] elements, IEnumerable<string> columnNames, bool @readonly = false) : base(elements, columnNames, @readonly) { }
     public DoubleMatrix(double[,] elements, IEnumerable<string> columnNames, IEnumerable<string> rowNames, bool @readonly = false) : base(elements, columnNames, rowNames, @readonly) { }
+    
+    public static DoubleMatrix FromRows(IList<double[]> elements, bool @readonly = false, IEnumerable<string> columnNames = null, IEnumerable<string> rowNames = null) {
+      if (elements.Count == 0) return new DoubleMatrix(0, 0);
+      var mat = new double[elements.Count, elements[0].Length];
+      for (var r = 0; r < mat.GetLength(0); r++)
+        for (var c = 0; c < mat.GetLength(1); c++)
+          mat[r, c] = elements[r][c];
+      // TODO: We should avoid the memory copy in this case
+      return new DoubleMatrix(mat, columnNames, rowNames, @readonly);
+    }
+    public static DoubleMatrix FromColumns(IList<double[]> elements, bool @readonly = false, IEnumerable<string> columnNames = null, IEnumerable<string> rowNames = null) {
+      if (elements.Count == 0) return new DoubleMatrix(0, 0);
+      var mat = new double[elements[0].Length, elements.Count];
+      for (var c = 0; c < mat.GetLength(1); c++)
+        for (var r = 0; r < mat.GetLength(0); r++)
+          mat[r, c] = elements[c][r];
+      // TODO: We should avoid the memory copy in this case
+      return new DoubleMatrix(mat, columnNames, rowNames, @readonly);
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/ValueTypeMatrix.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/ValueTypeMatrix.cs	(revision 17689)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Data/3.3/ValueTypeMatrix.cs	(revision 17690)
@@ -202,4 +202,14 @@
     }
 
+    public IEnumerable<T[]> CloneByRows() {
+      for (var r = 0; r < matrix.GetLength(0); r++)
+        yield return GetRow(r).ToArray();
+    }
+
+    public IEnumerable<T[]> CloneByColumn() {
+      for (var c = 0; c < matrix.GetLength(1); c++)
+        yield return GetColumn(c).ToArray();
+    }
+
     public virtual IEnumerable<T> GetRow(int row) {
       for (var col = 0; col < Columns; col++) {
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/BasicProblems/MultiObjectiveProblem.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/BasicProblems/MultiObjectiveProblem.cs	(revision 17689)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/BasicProblems/MultiObjectiveProblem.cs	(revision 17690)
@@ -38,17 +38,9 @@
     where TEncoding : class, IEncoding<TEncodedSolution>
     where TEncodedSolution : class, IEncodedSolution {
-    #region Parameter names
-    public const string BestKnownFrontParameterName = "BestKnownFront";
-    public const string ReferencePointParameterName = "ReferencePoint";
-    #endregion
 
     #region Parameter properties
     [Storable] public IValueParameter<BoolArray> MaximizationParameter { get; }
-    public IValueParameter<DoubleMatrix> BestKnownFrontParameter {
-      get { return (IValueParameter<DoubleMatrix>)Parameters[BestKnownFrontParameterName]; }
-    }
-    public IValueParameter<DoubleArray> ReferencePointParameter {
-      get { return (IValueParameter<DoubleArray>)Parameters[ReferencePointParameterName]; }
-    }
+    [Storable] public IValueParameter<DoubleMatrix> BestKnownFrontParameter { get; }
+    [Storable] public IValueParameter<DoubleArray> ReferencePointParameter { get; }
     #endregion
 
@@ -60,12 +52,13 @@
       : base(original, cloner) {
       MaximizationParameter = cloner.Clone(original.MaximizationParameter);
+      BestKnownFrontParameter = cloner.Clone(original.BestKnownFrontParameter);
+      ReferencePointParameter = cloner.Clone(original.ReferencePointParameter);
       ParameterizeOperators();
     }
 
     protected MultiObjectiveProblem(TEncoding encoding) : base(encoding) {
-      MaximizationParameter = new ValueParameter<BoolArray>("Maximization", "The dimensions correspond to the different objectives: False if the objective should be minimized, true if it should be maximized..", new BoolArray(new bool[] { }, @readonly: true));
-      Parameters.Add(MaximizationParameter);
-      Parameters.Add(new OptionalValueParameter<DoubleMatrix>(BestKnownFrontParameterName, "A double matrix representing the best known qualites for this problem (aka points on the Pareto front). Points are to be given in a row-wise fashion."));
-      Parameters.Add(new OptionalValueParameter<DoubleArray>(ReferencePointParameterName, "The reference point for hypervolume calculations on this problem"));
+      Parameters.Add(MaximizationParameter = new ValueParameter<BoolArray>("Maximization", "The dimensions correspond to the different objectives: False if the objective should be minimized, true if it should be maximized..", new BoolArray(new bool[] { }, @readonly: true)));
+      Parameters.Add(BestKnownFrontParameter = new OptionalValueParameter<DoubleMatrix>("Best Known Front", "A double matrix representing the best known qualites for this problem (aka points on the Pareto front). Points are to be given in a row-wise fashion."));
+      Parameters.Add(ReferencePointParameter = new OptionalValueParameter<DoubleArray>("Reference Point", "The reference point for hypervolume calculations on this problem"));
       Operators.Add(Evaluator);
       Operators.Add(new MultiObjectiveAnalyzer<TEncodedSolution>());
@@ -92,33 +85,18 @@
     public virtual IReadOnlyList<double[]> BestKnownFront {
       get {
-        if (!Parameters.ContainsKey(BestKnownFrontParameterName)) return null;
         var mat = BestKnownFrontParameter.Value;
         if (mat == null) return null;
-        var v = new double[mat.Rows][];
-        for (var i = 0; i < mat.Rows; i++) {
-          var r = v[i] = new double[mat.Columns];
-          for (var j = 0; j < mat.Columns; j++) {
-            r[j] = mat[i, j];
-          }
-        }
-        return v;
-      }
-      set {
-        if (value == null || value.Count == 0) {
-          BestKnownFrontParameter.Value = new DoubleMatrix();
-          return;
-        }
-        var mat = new DoubleMatrix(value.Count, value[0].Length);
-        for (int i = 0; i < value.Count; i++) {
-          for (int j = 0; j < value[i].Length; j++) {
-            mat[i, j] = value[i][j];
-          }
-        }
-
-        BestKnownFrontParameter.Value = mat;
+        return mat.CloneByRows().ToList();
       }
     }
+    public virtual void SetBestKnownFront(IList<double[]> front) {
+      if (front == null || front.Count == 0) {
+        BestKnownFrontParameter.Value = null;
+        return;
+      }
+      BestKnownFrontParameter.Value = DoubleMatrix.FromRows(front);
+    }
     public virtual double[] ReferencePoint {
-      get { return ReferencePointParameter.Value != null ? ReferencePointParameter.Value.CloneAsArray() : null; }
+      get { return ReferencePointParameter.Value?.CloneAsArray(); }
       set { ReferencePointParameter.Value = new DoubleArray(value); }
     }
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TestFunctions.MultiObjective/3.3/MultiObjectiveTestFunctionProblem.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TestFunctions.MultiObjective/3.3/MultiObjectiveTestFunctionProblem.cs	(revision 17689)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TestFunctions.MultiObjective/3.3/MultiObjectiveTestFunctionProblem.cs	(revision 17690)
@@ -19,4 +19,5 @@
  */
 #endregion
+
 using System;
 using System.Threading;
@@ -75,4 +76,6 @@
 
       BestKnownFrontParameter.Hidden = true;
+      BestKnownFrontParameter.ReadOnly = true;
+      ReferencePointParameter.ReadOnly = true;
 
       UpdateParameterValues();
@@ -82,6 +85,6 @@
 
     private void RegisterEventHandlers() {
-      TestFunctionParameter.ValueChanged += TestFunctionParameterOnValueChanged;
-      ObjectivesParameter.Value.ValueChanged += ObjectivesOnValueChanged;
+      IntValueParameterChangeHandler.Create(ObjectivesParameter, ObjectivesOnChanged);
+      ParameterChangeHandler<IMultiObjectiveTestFunction>.Create(TestFunctionParameter, TestFunctionOnChanged);
     }
 
@@ -113,28 +116,4 @@
 
     #region Events
-    private void UpdateParameterValues() {
-      Maximization = TestFunction.Maximization(Objectives);
-
-      Parameters.Remove(BestKnownFrontParameterName);
-      var front = TestFunction.OptimalParetoFront(Objectives);
-      var bkf = front != null ? (DoubleMatrix)Utilities.ToMatrix(front).AsReadOnly() : null;
-      Parameters.Add(new FixedValueParameter<DoubleMatrix>(BestKnownFrontParameterName, "A double matrix representing the best known qualities for this problem (aka points on the Pareto front). Points are to be given in a row-wise fashion.", bkf));
-
-      Parameters.Remove(ReferencePointParameterName);
-      Parameters.Add(new FixedValueParameter<DoubleArray>(ReferencePointParameterName, "The reference point for hypervolume calculations on this problem", new DoubleArray(TestFunction.ReferencePoint(Objectives))));
-
-      BoundsRefParameter.Value = new DoubleMatrix(TestFunction.Bounds(Objectives));
-    }
-
-    protected override void OnEncodingChanged() {
-      base.OnEncodingChanged();
-      UpdateParameterValues();
-    }
-
-    protected override void OnEvaluatorChanged() {
-      base.OnEvaluatorChanged();
-      UpdateParameterValues();
-    }
-
     protected override void DimensionOnChanged() {
       base.DimensionOnChanged();
@@ -142,22 +121,31 @@
         Dimension = Math.Min(TestFunction.MaximumSolutionLength, Math.Max(TestFunction.MinimumSolutionLength, Dimension));
       UpdateParameterValues();
+      OnReset();
     }
 
-    private void TestFunctionParameterOnValueChanged(object sender, EventArgs eventArgs) {
+    protected virtual void TestFunctionOnChanged() {
       Dimension = Math.Max(TestFunction.MinimumSolutionLength, Math.Min(Dimension, TestFunction.MaximumSolutionLength));
       Objectives = Math.Max(TestFunction.MinimumObjectives, Math.Min(Objectives, TestFunction.MaximumObjectives));
-      Parameters.Remove(ReferencePointParameterName);
-      Parameters.Add(new FixedValueParameter<DoubleArray>(ReferencePointParameterName, "The reference point for hypervolume calculations on this problem", new DoubleArray(TestFunction.ReferencePoint(Objectives))));
       UpdateParameterValues();
       OnReset();
     }
 
-    private void ObjectivesOnValueChanged(object sender, EventArgs eventArgs) {
+    protected virtual void ObjectivesOnChanged() {
       Objectives = Math.Min(TestFunction.MaximumObjectives, Math.Max(TestFunction.MinimumObjectives, Objectives));
       UpdateParameterValues();
+      OnReset();
     }
     #endregion
 
     #region Helpers
+    private void UpdateParameterValues() {
+      Maximization = TestFunction.Maximization(Objectives);
+
+      BestKnownFrontParameter.Value = DoubleMatrix.FromRows(TestFunction.OptimalParetoFront(Objectives));
+      ReferencePoint = TestFunction.ReferencePoint(Objectives);
+
+      BoundsRefParameter.Value = new DoubleMatrix(TestFunction.Bounds(Objectives));
+    }
+
     private void InitializeOperators() {
       Operators.Add(new CrowdingAnalyzer());
