Index: stable/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs
===================================================================
--- stable/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs	(revision 9736)
+++ stable/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs	(revision 9737)
@@ -53,4 +53,5 @@
 
     protected override void DeregisterContentEvents() {
+      Content.ElementNamesChanged -= new EventHandler(Content_ElementNamesChanged);
       Content.ItemChanged -= new EventHandler<EventArgs<int>>(Content_ItemChanged);
       Content.Reset -= new EventHandler(Content_Reset);
@@ -62,4 +63,5 @@
       Content.ItemChanged += new EventHandler<EventArgs<int>>(Content_ItemChanged);
       Content.Reset += new EventHandler(Content_Reset);
+      Content.ElementNamesChanged += new EventHandler(Content_ElementNamesChanged);
     }
 
@@ -96,5 +98,25 @@
         dataGridView.Columns[0].Width = dataGridView.Columns[0].GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);
       }
+      UpdateRowHeaders();
+      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
       dataGridView.Enabled = true;
+    }
+
+    protected virtual void UpdateRowHeaders() {
+      int i = 0;
+      foreach (string elementName in Content.ElementNames) {
+        dataGridView.Rows[i].HeaderCell.Value = elementName;
+        i++;
+      }
+      for (; i < dataGridView.RowCount; i++) {
+        dataGridView.Rows[i].HeaderCell.Value = string.Empty;
+      }
+    }
+
+    private void Content_ElementNamesChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_ElementNamesChanged), sender, e);
+      else
+        UpdateRowHeaders();
     }
 
Index: stable/HeuristicLab.Data/3.3/Interfaces/IStringConvertibleArray.cs
===================================================================
--- stable/HeuristicLab.Data/3.3/Interfaces/IStringConvertibleArray.cs	(revision 9736)
+++ stable/HeuristicLab.Data/3.3/Interfaces/IStringConvertibleArray.cs	(revision 9737)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using HeuristicLab.Common;
 
@@ -26,4 +27,5 @@
   public interface IStringConvertibleArray : IContent {
     int Length { get; set; }
+    IEnumerable<string> ElementNames { get; set; }
 
     bool ReadOnly { get; }
@@ -33,4 +35,5 @@
     bool SetValue(string value, int index);
 
+    event EventHandler ElementNamesChanged;
     event EventHandler<EventArgs<int>> ItemChanged;
     event EventHandler Reset;
Index: stable/HeuristicLab.Data/3.3/StringArray.cs
===================================================================
--- stable/HeuristicLab.Data/3.3/StringArray.cs	(revision 9736)
+++ stable/HeuristicLab.Data/3.3/StringArray.cs	(revision 9737)
@@ -43,4 +43,20 @@
     protected string[] array;
 
+    [Storable]
+    protected List<string> elementNames;
+    public virtual IEnumerable<string> ElementNames {
+      get { return this.elementNames; }
+      set {
+        if (ReadOnly) throw new NotSupportedException("ElementNames cannot be set. ValueTypeArray is read-only.");
+        if (value == null || !value.Any())
+          elementNames = new List<string>();
+        else if (value.Count() > Length)
+          throw new ArgumentException("The number of element names must not exceed the array length.");
+        else
+          elementNames = new List<string>(value);
+        OnElementNamesChanged();
+      }
+    }
+
     public virtual int Length {
       get { return array.Length; }
@@ -49,4 +65,7 @@
         if (value != Length) {
           Array.Resize<string>(ref array, value);
+          while (elementNames.Count > value)
+            elementNames.RemoveAt(elementNames.Count - 1);
+          OnElementNamesChanged();
           OnReset();
         }
@@ -72,4 +91,9 @@
     }
 
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (elementNames == null) { elementNames = new List<string>(); }
+    }
+
     [StorableConstructor]
     protected StringArray(bool deserializing) : base(deserializing) { }
@@ -78,8 +102,10 @@
       this.array = (string[])original.array.Clone();
       this.readOnly = original.readOnly;
+      this.elementNames = new List<string>(original.elementNames);
     }
     public StringArray() {
       array = new string[0];
       readOnly = false;
+      elementNames = new List<string>();
     }
     public StringArray(int length) {
@@ -88,4 +114,5 @@
         array[i] = string.Empty;
       readOnly = false;
+      elementNames = new List<string>();
     }
     public StringArray(string[] elements) {
@@ -95,4 +122,5 @@
         array[i] = elements[i] == null ? string.Empty : elements[i];
       readOnly = false;
+      elementNames = new List<string>();
     }
 
@@ -153,4 +181,11 @@
     }
 
+    public event EventHandler ElementNamesChanged;
+    protected virtual void OnElementNamesChanged() {
+      EventHandler handler = ElementNamesChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
     public event EventHandler<EventArgs<int>> ItemChanged;
     protected virtual void OnItemChanged(int index) {
Index: stable/HeuristicLab.Data/3.3/ValueTypeArray.cs
===================================================================
--- stable/HeuristicLab.Data/3.3/ValueTypeArray.cs	(revision 9736)
+++ stable/HeuristicLab.Data/3.3/ValueTypeArray.cs	(revision 9737)
@@ -43,4 +43,20 @@
     protected T[] array;
 
+    [Storable]
+    protected List<string> elementNames;
+    public virtual IEnumerable<string> ElementNames {
+      get { return this.elementNames; }
+      set {
+        if (ReadOnly) throw new NotSupportedException("ElementNames cannot be set. ValueTypeArray is read-only.");
+        if (value == null || !value.Any())
+          elementNames = new List<string>();
+        else if (value.Count() > Length)
+          throw new ArgumentException("The number of element names must not exceed the array length.");
+        else
+          elementNames = new List<string>(value);
+        OnElementNamesChanged();
+      }
+    }
+
     public virtual int Length {
       get { return array.Length; }
@@ -51,4 +67,7 @@
         if (value != Length) {
           Array.Resize<T>(ref array, value);
+          while (elementNames.Count > value)
+            elementNames.RemoveAt(elementNames.Count - 1);
+          OnElementNamesChanged();
           OnReset();
         }
@@ -73,4 +92,9 @@
     }
 
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (elementNames == null) { elementNames = new List<string>(); }
+    }
+
     [StorableConstructor]
     protected ValueTypeArray(bool deserializing) : base(deserializing) { }
@@ -79,12 +103,15 @@
       this.array = (T[])original.array.Clone();
       this.readOnly = original.readOnly;
+      this.elementNames = new List<string>(original.elementNames);
     }
     protected ValueTypeArray() {
       array = new T[0];
       readOnly = false;
+      elementNames = new List<string>();
     }
     protected ValueTypeArray(int length) {
       array = new T[length];
       readOnly = false;
+      elementNames = new List<string>();
     }
     protected ValueTypeArray(T[] elements) {
@@ -92,4 +119,5 @@
       array = (T[])elements.Clone();
       readOnly = false;
+      elementNames = new List<string>();
     }
 
@@ -125,4 +153,11 @@
     }
 
+    public event EventHandler ElementNamesChanged;
+    protected virtual void OnElementNamesChanged() {
+      EventHandler handler = ElementNamesChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
     public event EventHandler<EventArgs<int>> ItemChanged;
     protected virtual void OnItemChanged(int index) {
