 		{
 			binningDefinition.requestLocalObject(SimpleBinningDefinition, false);
 
-			addImmediateCallback(this, invalidateBins);
-			// when derived bins change, invalidate them
-			// this is to prevent changes to the derivedBins from affecting the internal code.
-			_derivedBins.addImmediateCallback(this, handleDerivedBinsChange);
+			addImmediateCallback(this, handleChange);
 		}
 		
 		/**

			return _derivedBins;
		}
		
		private const _derivedBins:BinClassifierCollection = newDisposableChild(this, BinClassifierCollection); // returned by public getter
		private var _binNames:Array = null; // maps a bin index to a bin name
		private var _keyToBinIndexMap:Dictionary = null; // maps a record key to a bin index
		private var _binnedKeysArray:Array = null; // maps a bin index to a list of keys in that bin

		 * and also saves lookups for mapping between bins and keys.
		 */
		private function validateBins():void
		{
			_dirty = false;
			_derivedBins.delayCallbacks(); // make sure callbacks don't run until we're done
			
			_column = internalDynamicColumn.getInternalColumn();
			_def = (binningDefinition.internalObject as IBinningDefinition);
			// reset cached values
			_keyToBinIndexMap = new Dictionary();
			_binnedKeysArray = [];
			_binnedKeysMap = {};
			_largestBinSize = 0;
			_derivedBins.removeAllObjects();
			if (_def != null && _column != null)
				_def.getBinClassifiersForColumn(_column, _derivedBins);
			// save bin names for faster lookup
			_binNames = _derivedBins.getNames();
			var bins:Array = _derivedBins.getObjects();
			var i:int;
			// create empty key arrays
			for (i = 0; i < _binNames.length; i++)
				_binnedKeysMap[_binNames[i]] = _binnedKeysArray[i] = []; // same Array pointer
			// fill all mappings
			_keys = keys;
			_i = 0;
			WeaveAPI.StageUtils.startTask(this, _asyncIterate, WeaveAPI.TASK_PRIORITY_BUILDING, _asyncComplete);
		}
		
		private var _column:IAttributeColumn;
		private var _def:IBinningDefinition;
		private var _i:int;
		private var _keys:Array;
		private function _asyncIterate():Number
		{
			var progress:Number = 1;
			if (_i < _keys.length)
			{
				var key:IQualifiedKey = keys[_i];
				// hack: assuming bin classifiers are NumberClassifiers except for CategoryBinningDefinition
				var dataType:Class = _def is CategoryBinningDefinition ? String : Number;
				var value:* = _column.getValueFromKey(key, dataType);
				var binIndex:Number = _derivedBins.getBinIndexFromDataValue(value);
				if (!isNaN(binIndex))
				{
					_keyToBinIndexMap[key] = binIndex;
					var array:Array = _binnedKeysArray[binIndex] as Array;
					if (array.push(key) > _largestBinSize)
						_largestBinSize = array.length;
				}
				progress = _i++ / _keys.length;
			}
			return progress;
		}
		
		private function _asyncComplete():void
		{
			_validateBinsCompleted = true; // tells handleChange() that the bins are now valid
			_derivedBins.resumeCallbacks(true); // allow callbacks to run now
		}

		/**
