Index: /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.Designer.cs
===================================================================
--- /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.Designer.cs	(revision 12214)
+++ /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.Designer.cs	(revision 12215)
@@ -158,4 +158,5 @@
       this.searchTextBox.TabIndex = 1;
       this.searchTextBox.TextChanged += new System.EventHandler(this.searchTextBox_TextChanged);
+      this.searchTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.searchTextBox_KeyDown);
       // 
       // clearSearchButton
Index: /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.cs
===================================================================
--- /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.cs	(revision 12214)
+++ /branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.cs	(revision 12215)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Drawing;
@@ -30,4 +31,6 @@
 namespace HeuristicLab.Optimizer {
   internal partial class NewItemDialog : Form {
+    private const string RootMarker = "<ROOT>";
+
     private bool isInitialized;
 
@@ -63,42 +66,103 @@
 
       var categories =
-        from t in ApplicationManager.Manager.GetTypes(typeof(IItem))
-        where CreatableAttribute.IsCreatable(t)
-        orderby CreatableAttribute.GetCategory(t), ItemAttribute.GetName(t), ItemAttribute.GetVersion(t) ascending
-        group t by CreatableAttribute.GetCategory(t) into c
-        select c;
-
+        from type in ApplicationManager.Manager.GetTypes(typeof(IItem))
+        let category = CreatableAttribute.GetCategory(type)
+        let name = ItemAttribute.GetName(type)
+        let version = ItemAttribute.GetVersion(type)
+        where CreatableAttribute.IsCreatable(type)
+        orderby category, name, version ascending
+        group type by category into categoryGroup
+        select categoryGroup;
+
+      var rootNode = CreateCategoryTree(categories);
+      CreateItemNodes(rootNode, categories);
+
+      foreach (TreeNode topNode in rootNode.Nodes)
+        treeNodes.Add(topNode);
+      foreach (var node in treeNodes)
+        typesTreeView.Nodes.Add((TreeNode)node.Clone());
+
+      typesTreeView.TreeViewNodeSorter = new ItemTreeNodeComparer();
+      typesTreeView.Sort();
+
+      isInitialized = true;
+    }
+
+    private TreeNode CreateCategoryTree(IEnumerable<IGrouping<string, Type>> categories) {
       imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class);      // default icon
       imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Namespace);  // plugins
 
+      var rootNode = new TreeNode(RootMarker) { Name = RootMarker, Tag = RootMarker };
+
       foreach (var category in categories) {
-        var categoryNode = new TreeNode(category.Key) {
-          ImageIndex = 1,
-          Tag = category.Key,
+        var categoryFullName = category.Key;
+        var categoryTokens = categoryFullName.Split('#');
+        var categoryName = categoryTokens.Last();
+        var parentCategories = categoryTokens.Take(categoryTokens.Length - 1);
+
+        var categoryNode = new TreeNode(categoryName, 1, 1) {
+          Name = categoryName,
+          Tag = categoryName
         };
-        categoryNode.SelectedImageIndex = categoryNode.ImageIndex;
-
+
+        var parentNode = FindOrCreateParentNode(rootNode, parentCategories);
+        if (parentNode != null)
+          parentNode.Nodes.Add(categoryNode);
+        else
+          rootNode.Nodes.Add(categoryNode);
+      }
+
+      return rootNode;
+    }
+    private TreeNode FindOrCreateParentNode(TreeNode node, IEnumerable<string> parentCategories) {
+      TreeNode parentNode = null;
+      foreach (string parentCategory in parentCategories) {
+        parentNode = node.Nodes.Find(parentCategory, searchAllChildren: false).SingleOrDefault();
+        if (parentNode == null) {
+          parentNode = new TreeNode(parentCategory, 1, 1) {
+            Name = parentCategory,
+            Tag = parentCategory
+          };
+          node.Nodes.Add(parentNode);
+        }
+        node = parentNode;
+      }
+      return parentNode;
+    }
+
+    private void CreateItemNodes(TreeNode node, IEnumerable<IGrouping<string, Type>> categories) {
+      foreach (var category in categories) {
+        var categoryNode = FindCategoryNode(node, category.Key);
         foreach (var creatable in category) {
-          string name = ItemAttribute.GetName(creatable);
-
-          var itemNode = new TreeNode(name) {
-            ImageIndex = 0,
-            Tag = creatable
-          };
+          var itemNode = CreateItemNode(creatable);
           categoryNode.Nodes.Add(itemNode);
-          var image = ItemAttribute.GetImage(creatable);
-          if (image != null) {
-            imageList.Images.Add(image);
-            itemNode.ImageIndex = imageList.Images.Count - 1;
-          }
-          itemNode.SelectedImageIndex = itemNode.ImageIndex;
-        }
-        if (categoryNode.Nodes.Count > 0)
-          treeNodes.Add(categoryNode);
-      }
-      foreach (var node in treeNodes)
-        typesTreeView.Nodes.Add((TreeNode)node.Clone());
-      isInitialized = true;
-    }
+        }
+      }
+    }
+    private TreeNode FindCategoryNode(TreeNode node, string fullCategoryName) {
+      var categories = fullCategoryName.Split('#');
+      foreach (string category in categories)
+        node = node.Nodes.Find(category, searchAllChildren: false).Single();
+      return node;
+    }
+
+    private TreeNode CreateItemNode(Type creatable) {
+      string name = ItemAttribute.GetName(creatable);
+
+      var itemNode = new TreeNode(name) {
+        ImageIndex = 0,
+        Tag = creatable
+      };
+
+      var image = ItemAttribute.GetImage(creatable);
+      if (image != null) {
+        imageList.Images.Add(image);
+        itemNode.ImageIndex = imageList.Images.Count - 1;
+      }
+      itemNode.SelectedImageIndex = itemNode.ImageIndex;
+
+      return itemNode;
+    }
+
     private void NewItemDialog_Shown(object sender, EventArgs e) {
       searchTextBox.Text = string.Empty;
@@ -131,5 +195,6 @@
           while (j < typesTreeView.Nodes[i].Nodes.Count) {
             if (searchTokens.Any(searchToken => !typesTreeView.Nodes[i].Nodes[j].Text.ToLower().Contains(searchToken))) {
-              if ((typesTreeView.Nodes[i].Nodes[j].Tag as Type).Equals(SelectedType))
+              var node = typesTreeView.Nodes[i].Nodes[j];
+              if (node != null && node.Tag is Type && (node.Tag as Type).Equals(SelectedType))
                 SelectedType = null;
               typesTreeView.Nodes[i].Nodes[j].Remove();
@@ -313,4 +378,42 @@
       searchTextBox.Focus();
     }
+
+    private void searchTextBox_KeyDown(object sender, KeyEventArgs e) {
+      if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) {
+
+        int? idx = typesTreeView.SelectedNode != null
+          ? (int?)typesTreeView.SelectedNode.Index
+          : null;
+
+        TreeNode newNode = null;
+        if (e.KeyCode == Keys.Down) {
+          if (idx.HasValue && idx < typesTreeView.Nodes.Count - 1) {
+            newNode = typesTreeView.Nodes[idx.Value + 1];
+          } else if (typesTreeView.Nodes.Count > 0) {
+            newNode = typesTreeView.Nodes[0];
+          }
+        } else if (e.KeyCode == Keys.Up && idx.HasValue && idx > 0) {
+          newNode = typesTreeView.Nodes[idx.Value - 1];
+        }
+
+        if (newNode != null)
+          typesTreeView.SelectedNode = newNode;
+        e.Handled = true;
+      }
+    }
+
+    private class ItemTreeNodeComparer : IComparer {
+      public int Compare(object x, object y) {
+        var lhs = (TreeNode)x;
+        var rhs = (TreeNode)y;
+
+        if (lhs.Tag is string && rhs.Tag is string) {
+          return lhs.Name.CompareTo(rhs.Name);
+        } else if (lhs.Tag is string) {
+          return -1;
+        } else
+          return 1;
+      }
+    }
   }
 }
