// Called when an item is added to the items collection
        void OnItemAdded(object item, int index)
        {
            if (_itemMap == null)
            {
                // reentrant call (from RemoveAllInternal) shouldn't happen,
                // but if it does, don't crash
                Debug.Assert(false, "unexpected reentrant call to OnItemAdded");
                return;
            }

            ValidateAndCorrectIndex(item, ref index);

            GeneratorPosition position = new GeneratorPosition(-1,0);

            // find the block containing the new item
            ItemBlock block = _itemMap.Next;
            int offset = index;
            while (block != _itemMap && offset >= block.ItemCount)
            {
                offset -= block.ItemCount;
                position.Index += block.ContainerCount;
                block = block.Next;
            }

            position.Offset = offset + 1;

            // if it's an unrealized block, add the item by bumping the count
            UnrealizedItemBlock uib = block as UnrealizedItemBlock;
            if (uib != null)
            {
                MoveItems(uib, offset, 1, uib, offset+1, 0);
                ++ uib.ItemCount;
            }

            // if the item can be added to a previous unrealized block, do so
            else if ((offset == 0 || block == _itemMap) &&
                    ((uib = block.Prev as UnrealizedItemBlock) != null))
            {
                ++ uib.ItemCount;
            }

            // otherwise, create a new unrealized block
            else
            {
                uib = new UnrealizedItemBlock();
                uib.ItemCount = 1;

                // split the current realized block, if necessary
                RealizedItemBlock rib;
                if (offset > 0 && (rib = block as RealizedItemBlock) != null)
                {
                    RealizedItemBlock newBlock = new RealizedItemBlock();
                    MoveItems(rib, offset, rib.ItemCount - offset, newBlock, 0, offset);
                    newBlock.InsertAfter(rib);
                    position.Index += block.ContainerCount;
                    position.Offset = 1;
                    block = newBlock;
                }

                uib.InsertBefore(block);
            }

            // tell generators what happened
            if (MapChanged != null)
            {
                MapChanged(null, index, +1, uib, 0, 0);
            }

            // tell layout what happened
            if (ItemsChanged != null)
            {
                ItemsChanged(this, new ItemsChangedEventArgs(NotifyCollectionChangedAction.Add, position, 1, 0));
            }
        }
        void OnItemMoved(object item, int oldIndex, int newIndex)
        {
            if (_itemMap == null)
            {
                // reentrant call (from RemoveAllInternal) shouldn't happen,
                // but if it does, don't crash
                Debug.Assert(false, "unexpected reentrant call to OnItemMoved");
                return;
            }

            DependencyObject container = null;    // the corresponding container
            int containerCount = 0;
            UnrealizedItemBlock uib;

            // search for the moved item
            GeneratorPosition position;
            ItemBlock block;
            int offsetFromBlockStart;
            int correctIndex;
            GetBlockAndPosition(item, oldIndex, true, out position, out block, out offsetFromBlockStart, out correctIndex);

            GeneratorPosition oldPosition = position;

            RealizedItemBlock rib = block as RealizedItemBlock;
            if (rib != null)
            {
                containerCount = 1;
                container = rib.ContainerAt(offsetFromBlockStart);
            }

            // remove the item, and remove the block if it's now empty
            MoveItems(block, offsetFromBlockStart + 1, block.ItemCount - offsetFromBlockStart - 1, block, offsetFromBlockStart, 0);
            --block.ItemCount;
            RemoveAndCoalesceBlocksIfNeeded(block);

            //
            // now insert into the new spot.
            //

            position = new GeneratorPosition(-1,0);
            block = _itemMap.Next;
            offsetFromBlockStart = newIndex;
            while (block != _itemMap && offsetFromBlockStart >= block.ItemCount)
            {
                offsetFromBlockStart -= block.ItemCount;
                if (block.ContainerCount > 0)
                {
                    position.Index += block.ContainerCount;
                    position.Offset = 0;
                }
                else
                {
                    position.Offset += block.ItemCount;
                }
                block = block.Next;
            }

            position.Offset += offsetFromBlockStart + 1;

            // if it's an unrealized block, add the item by bumping the count
            uib = block as UnrealizedItemBlock;
            if (uib != null)
            {
                MoveItems(uib, offsetFromBlockStart, 1, uib, offsetFromBlockStart+1, 0);
                ++ uib.ItemCount;
            }

            // if the item can be added to a previous unrealized block, do so
            else if ((offsetFromBlockStart == 0 || block == _itemMap) &&
                    ((uib = block.Prev as UnrealizedItemBlock) != null))
            {
                ++ uib.ItemCount;
            }

            // otherwise, create a new unrealized block
            else
            {
                uib = new UnrealizedItemBlock();
                uib.ItemCount = 1;

                // split the current realized block, if necessary
                if (offsetFromBlockStart > 0 && (rib = block as RealizedItemBlock) != null)
                {
                    RealizedItemBlock newBlock = new RealizedItemBlock();
                    MoveItems(rib, offsetFromBlockStart, rib.ItemCount - offsetFromBlockStart, newBlock, 0, offsetFromBlockStart);
                    newBlock.InsertAfter(rib);
                    position.Index += block.ContainerCount;
                    position.Offset = 1;
                    offsetFromBlockStart = 0;
                    block = newBlock;
                }

                uib.InsertBefore(block);
            }

            DependencyObject parent = VisualTreeHelper.GetParentInternal(container);

            // tell layout what happened
            if (ItemsChanged != null)
            {
                ItemsChanged(this, new ItemsChangedEventArgs(NotifyCollectionChangedAction.Move, position, oldPosition, 1, containerCount));
            }

            // unhook the container.  Do this after layout has (presumably) removed it from
            // the UI, so that it doesn't inherit DataContext falsely.
            if (container != null)
            {
                if (parent == null || VisualTreeHelper.GetParentInternal(container) != parent)
                {
                    UnlinkContainerFromItem(container, item);
                }
                else
                {
                    // If the container has the same visual parent as before then that means that
                    // the container was just repositioned within the parent's VisualCollection.
                    // we don't need to unlink the container, but we do need to re-realize the block.
                    Realize(uib, offsetFromBlockStart, item, container);
                }
            }

            // fix up the AlternationIndex on containers affected by the move
            if (_alternationCount > 0)
            {
                // start with the smaller of the two positions, and proceed forward.
                // This tends to preserve the AlternatonIndex on containers at the
                // front of the list, as users expect
                int index = Math.Min(oldIndex, newIndex);
                GetBlockAndPosition(index, out position, out block, out offsetFromBlockStart);
                SetAlternationIndex(block, offsetFromBlockStart, GeneratorDirection.Forward);
            }
        }
        // Called when an item is added to the items collection 
        void OnItemAdded(object item, int index)
        { 
            ValidateAndCorrectIndex(item, ref index); 

            GeneratorPosition position = new GeneratorPosition(-1,0); 

            // find the block containing the new item
            ItemBlock block = _itemMap.Next;
            int offset = index; 
            while (block != _itemMap && offset >= block.ItemCount)
            { 
                offset -= block.ItemCount; 
                position.Index += block.ContainerCount;
                block = block.Next; 
            }

            position.Offset = offset + 1;
 
            // if it's an unrealized block, add the item by bumping the count
            UnrealizedItemBlock uib = block as UnrealizedItemBlock; 
            if (uib != null) 
            {
                MoveItems(uib, offset, 1, uib, offset+1, 0); 
                ++ uib.ItemCount;
            }

            // if the item can be added to a previous unrealized block, do so 
            else if ((offset == 0 || block == _itemMap) &&
                    ((uib = block.Prev as UnrealizedItemBlock) != null)) 
            { 
                ++ uib.ItemCount;
            } 

            // otherwise, create a new unrealized block
            else
            { 
                uib = new UnrealizedItemBlock();
                uib.ItemCount = 1; 
 
                // split the current realized block, if necessary
                RealizedItemBlock rib; 
                if (offset > 0 && (rib = block as RealizedItemBlock) != null)
                {
                    RealizedItemBlock newBlock = new RealizedItemBlock();
                    MoveItems(rib, offset, rib.ItemCount - offset, newBlock, 0, offset); 
                    newBlock.InsertAfter(rib);
                    position.Index += block.ContainerCount; 
                    position.Offset = 1; 
                    block = newBlock;
                } 

                uib.InsertBefore(block);
            }
 
            if (_traceLog != null)
                _traceLog.Add("OnItemAdded {0} index = {1}", TraceLog.IdFor(item), index); 
 
            // tell generators what happened
            if (MapChanged != null) 
            {
                MapChanged(null, index, +1, null, 0, 0);
            }
 
            // tell layout what happened
            if (ItemsChanged != null) 
            { 
                ItemsChanged(this, new ItemsChangedEventArgs(NotifyCollectionChangedAction.Add, position, 1, 0));
            } 
        }