diff -r f0a8403141d2 javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ListViewSkin.java
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ListViewSkin.java	Wed Sep 19 13:00:44 2012 -0400
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ListViewSkin.java	Wed Sep 19 20:04:18 2012 -0700
@@ -27,6 +27,8 @@
 
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
+import javafx.collections.ObservableMap;
+import javafx.collections.WeakListChangeListener;
 import javafx.event.EventHandler;
 import javafx.geometry.Orientation;
 import javafx.scene.Node;
@@ -36,11 +38,8 @@
 import javafx.scene.control.ListView;
 import javafx.scene.control.SelectionModel;
 import javafx.scene.input.MouseEvent;
-
-import javafx.collections.WeakListChangeListener;
+import javafx.util.Callback;
 import com.sun.javafx.scene.control.behavior.ListViewBehavior;
-import javafx.collections.ObservableMap;
-import javafx.util.Callback;
 
 /**
  *
@@ -192,7 +191,7 @@
         flow.setCellCount(newCount);
         
         if (newCount != oldCount) {
-            flow.recreateCells();
+            flow.rebuildCells();
         } else {
             flow.reconfigureCells();
         }
diff -r f0a8403141d2 javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableViewSkin.java
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableViewSkin.java	Wed Sep 19 13:00:44 2012 -0400
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableViewSkin.java	Wed Sep 19 20:04:18 2012 -0700
@@ -25,17 +25,22 @@
 package com.sun.javafx.scene.control.skin;
 
 import java.util.List;
-
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
+import javafx.beans.WeakInvalidationListener;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 import javafx.collections.FXCollections;
 import javafx.collections.ListChangeListener;
 import javafx.collections.MapChangeListener;
 import javafx.collections.ObservableList;
+import javafx.collections.ObservableMap;
+import javafx.collections.WeakListChangeListener;
 import javafx.event.EventHandler;
+import javafx.geometry.HPos;
 import javafx.geometry.Insets;
+import javafx.geometry.VPos;
 import javafx.scene.Node;
 import javafx.scene.control.Label;
 import javafx.scene.control.SelectionModel;
@@ -47,15 +52,8 @@
 import javafx.scene.layout.Region;
 import javafx.scene.layout.StackPane;
 import javafx.util.Callback;
-
 import com.sun.javafx.scene.control.behavior.TableViewBehavior;
-import javafx.collections.WeakListChangeListener;
 import com.sun.javafx.scene.control.skin.resources.ControlResources;
-import javafx.beans.WeakInvalidationListener;
-import javafx.beans.value.WeakChangeListener;
-import javafx.collections.ObservableMap;
-import javafx.geometry.HPos;
-import javafx.geometry.VPos;
 
 public class TableViewSkin<T> extends VirtualContainerBase<TableView<T>, TableViewBehavior<T>, TableRow<T>> {
     
@@ -688,10 +686,11 @@
         flow.setCellCount(newCount);
         
         if (newCount != oldCount) {
-            // FIXME updateRowCount is called _a lot_. Perhaps we can make recreateCells
+            // FIXME updateRowCount is called _a lot_. Perhaps we can make rebuildCells
             // smarter. Imagine if items has one million items added - do we really
-            // need to recreateCells a million times?
-            flow.recreateCells();
+            // need to rebuildCells a million times? Maybe this is better now that
+            // we do rebuildCells instead of recreateCells.
+            flow.rebuildCells();
         } else {
             flow.reconfigureCells();
         }
diff -r f0a8403141d2 javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java	Wed Sep 19 13:00:44 2012 -0400
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java	Wed Sep 19 20:04:18 2012 -0700
@@ -753,25 +753,38 @@
     }
 
     @Override protected void layoutChildren() {
-       if (needsRecreateCells) {
+        if (needsRecreateCells) {
             maxPrefBreadth = -1;
             lastWidth = -1;
             lastHeight = -1;
             releaseCell(accumCell);
 //            accumCell = null;
 //            accumCellParent.getChildren().clear();
+            for (int i=0; i<cells.size(); i++) {
+                cells.get(i).updateIndex(-1);
+            }
             cells.clear();
             pile.clear();
-            needsRecreateCells = false;
-        } 
-        
-        if (needsReconfigureCells) {
+        } else if (needsRebuildCells) {
             maxPrefBreadth = -1;
             lastWidth = -1;
             lastHeight = -1;
-            needsReconfigureCells = false;
+            releaseCell(accumCell);
+            for (int i=0; i<cells.size(); i++) {
+                cells.get(i).updateIndex(-1);
+            }
+            addAllToPile();
+        } else if (needsReconfigureCells) {
+            maxPrefBreadth = -1;
+            lastWidth = -1;
+            lastHeight = -1;
         }
-        
+
+        needsRecreateCells = false;
+        needsReconfigureCells = false;
+        needsRebuildCells = false;
+
+
         if (needsCellsLayout) {
             for (int i = 0, max = cells.size(); i < max; i++) {
                 Cell cell = cells.get(i);
@@ -1428,6 +1441,14 @@
             }
         }
 
+        if (pile.size() > 0) {
+            // TODO The above code checks for null values returned from the pile. Is that possible?
+            // TODO I would not have thought so, there should be an assert added to addToPile to
+            // TODO make sure we never add null to the pile (since it doesn't make sense to do so)
+            // TODO and then we can get rid of the cell != null check on line 1422 above.
+            return pile.get(0);
+        }
+
         // We need to use the accumCell and return that
         Callback<VirtualFlow,? extends IndexedCell> createCell = getCreateCell();
         if (accumCell == null && createCell != null) {
@@ -1905,8 +1926,9 @@
         return delta; // TODO fake
     }
 
-    private boolean needsReconfigureCells = false;
-    private boolean needsRecreateCells = false;
+    private boolean needsReconfigureCells = false; // when cell contents are the same
+    private boolean needsRecreateCells = false; // when cell factory changed
+    private boolean needsRebuildCells = false; // when cell contents have changed
     private boolean needsCellsLayout = false;
     
     public void reconfigureCells() {
@@ -1919,6 +1941,11 @@
         requestLayout();
     }
     
+    public void rebuildCells() {
+        needsRebuildCells = true;
+        requestLayout();
+    }
+
     public void requestCellLayout() {
         needsCellsLayout = true;
         requestLayout();
diff -r f0a8403141d2 javafx-ui-controls/src/javafx/scene/control/ListCell.java
--- a/javafx-ui-controls/src/javafx/scene/control/ListCell.java	Wed Sep 19 13:00:44 2012 -0400
+++ b/javafx-ui-controls/src/javafx/scene/control/ListCell.java	Wed Sep 19 20:04:18 2012 -0700
@@ -25,8 +25,8 @@
 
 package javafx.scene.control;
 
-import com.sun.javafx.logging.PlatformLogger;
-import com.sun.javafx.scene.control.Logging;
+import java.lang.ref.WeakReference;
+import java.util.List;
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.beans.WeakInvalidationListener;
@@ -37,12 +37,7 @@
 import javafx.beans.value.WeakChangeListener;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
-
 import javafx.collections.WeakListChangeListener;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import javafx.beans.property.ReadOnlyObjectProperty;
-import javafx.beans.property.ReadOnlyObjectWrapper;
 
 
 /**
@@ -166,7 +161,20 @@
      */
     private final ListChangeListener itemsListener = new ListChangeListener() {
         @Override public void onChanged(ListChangeListener.Change c) {
-            updateItem(); // TODO limit this to only those changes necessary
+            boolean needsUpdate = false;
+            while (c.next()) {
+                if (!c.wasAdded() && !c.wasRemoved()) {
+                    int idx = getIndex();
+                    needsUpdate = c.getFrom() <= idx && idx <= c.getTo();
+                    break;
+                }
+            }
+
+            if (needsUpdate) {
+                // Only call updateItem if there were items permuted, and only if
+                // the index of the permuted range includes this item.
+                updateItem();
+            }
         }
     };
 
