internal void RemoveAllInternal(bool saveRecycleQueue)
        {
            // Take _itemMap offline, to protect against reentrancy (bug 1285179)
            ItemBlock itemMap = _itemMap;
            _itemMap = null;

            try
            {
                // de-initialize the containers that are being removed
                if (itemMap != null)
                {
                    for (ItemBlock block = itemMap.Next;  block != itemMap;  block = block.Next)
                    {
                        RealizedItemBlock rib = block as RealizedItemBlock;
                        if (rib != null)
                        {
                            for (int offset = 0; offset < rib.ContainerCount; ++offset)
                            {
                                UnlinkContainerFromItem(rib.ContainerAt(offset), rib.ItemAt(offset));
                            }
                        }
                    }
                }
            }
            finally
            {
                PrepareGrouping();

                // re-initialize the data structure
                _itemMap = new ItemBlock();
                _itemMap.Prev = _itemMap.Next = _itemMap;

                UnrealizedItemBlock uib = new UnrealizedItemBlock();
                uib.InsertAfter(_itemMap);
                uib.ItemCount = ItemsInternal.Count;

                if (!saveRecycleQueue)
                {
                    ResetRecyclableContainers();
                }

                SetAlternationCount();

                // tell generators what happened
                if (MapChanged != null)
                {
                    MapChanged(null, -1, 0, uib, 0, 0);
                }
            }
        }
        /// <summary>
        /// Remove generated elements.
        /// </summary>
        private void Remove(GeneratorPosition position, int count, bool isRecycling)
        {
            if (position.Offset != 0)
                throw new ArgumentException(SR.Get(SRID.RemoveRequiresOffsetZero, position.Index, position.Offset), "position");
            if (count <= 0)
                throw new ArgumentException(SR.Get(SRID.RemoveRequiresPositiveCount, count), "count");

            if (_itemMap == null)
            {
                // ignore reentrant call (during RemoveAllInternal)
                Debug.Assert(false, "Unexpected reentrant call to ICG.Remove");
                return;
            }

            int index = position.Index;
            ItemBlock block;

            // find the leftmost item to remove
            int offsetL = index;
            for (block = _itemMap.Next;  block != _itemMap;  block = block.Next)
            {
                if (offsetL < block.ContainerCount)
                    break;

                offsetL -= block.ContainerCount;
            }
            RealizedItemBlock blockL = block as RealizedItemBlock;

            // find the rightmost item to remove
            int offsetR = offsetL + count - 1;
            for (; block != _itemMap;  block = block.Next)
            {
                if (!(block is RealizedItemBlock))
                    throw new InvalidOperationException(SR.Get(SRID.CannotRemoveUnrealizedItems, index, count));

                if (offsetR < block.ContainerCount)
                    break;

                offsetR -= block.ContainerCount;
            }
            RealizedItemBlock blockR = block as RealizedItemBlock;

            // de-initialize the containers that are being removed
            RealizedItemBlock rblock = blockL;
            int offset = offsetL;
            while (rblock != blockR || offset <= offsetR)
            {
                DependencyObject container = rblock.ContainerAt(offset);

                UnlinkContainerFromItem(container, rblock.ItemAt(offset));
                // DataGrid generates non-GroupItem for NewItemPlaceHolder
                // Dont recycle in this case.
                bool isNewItemPlaceHolderWhenGrouping = _generatesGroupItems && !(container is GroupItem);

                if (isRecycling && !isNewItemPlaceHolderWhenGrouping)
                {
                    Debug.Assert(!_recyclableContainers.Contains(container), "trying to add a container to the collection twice");

                    if (_containerType == null)
                    {
                        _containerType = container.GetType();
                    }
                    else if (_containerType != container.GetType())
                    {
                        throw new InvalidOperationException(SR.Get(SRID.CannotRecyleHeterogeneousTypes));
                    }

                    _recyclableContainers.Enqueue(container);
                }

                if (++offset >= rblock.ContainerCount && rblock != blockR)
                {
                    rblock = rblock.Next as RealizedItemBlock;
                    offset = 0;
                }
            }

            // see whether the range hits the edge of a block on either side,
            // and whether the a`butting block is an unrealized gap
            bool edgeL = (offsetL == 0);
            bool edgeR = (offsetR == blockR.ItemCount-1);
            bool abutL = edgeL && (blockL.Prev is UnrealizedItemBlock);
            bool abutR = edgeR && (blockR.Next is UnrealizedItemBlock);

            // determine the target (unrealized) block,
            // the offset within the target at which to insert items,
            // and the intial change in cumulative item count
            UnrealizedItemBlock blockT;
            ItemBlock predecessor = null;
            int offsetT;
            int deltaCount;

            if (abutL)
            {
                blockT = (UnrealizedItemBlock)blockL.Prev;
                offsetT = blockT.ItemCount;
                deltaCount = -blockT.ItemCount;
            }
            else if (abutR)
            {
                blockT = (UnrealizedItemBlock)blockR.Next;
                offsetT = 0;
                deltaCount = offsetL;
            }
            else
            {
                blockT = new UnrealizedItemBlock();
                offsetT = 0;
                deltaCount = offsetL;

                // remember where the new block goes, so we can insert it later
                predecessor = (edgeL) ? blockL.Prev : blockL;
            }

            // move items within the range to the target block
            for (block = blockL;  block != blockR;  block = block.Next)
            {
                int itemCount = block.ItemCount;
                MoveItems(block, offsetL, itemCount-offsetL,
                            blockT, offsetT, deltaCount);
                offsetT += itemCount-offsetL;
                offsetL = 0;
                deltaCount -= itemCount;
                if (block.ItemCount == 0)
                    block.Remove();
            }

            // the last block in the range is a little special...
            // Move the last unrealized piece.
            int remaining = block.ItemCount - 1 - offsetR;
            MoveItems(block, offsetL, offsetR - offsetL + 1,
                        blockT, offsetT, deltaCount);

            // Move the remaining realized items
            RealizedItemBlock blockX = blockR;
            if (!edgeR)
            {
                if (blockL == blockR && !edgeL)
                {
                    blockX = new RealizedItemBlock();
                }

                MoveItems(block, offsetR+1, remaining,
                            blockX, 0, offsetR+1);
            }

            // if we created any new blocks, insert them in the list
            if (predecessor != null)
                blockT.InsertAfter(predecessor);
            if (blockX != blockR)
                blockX.InsertAfter(blockT);

            RemoveAndCoalesceBlocksIfNeeded(block);

        }
        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)
        {
            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));
            }
        }
        // "Realize" the item in a block at the given offset, to be
        // the given item with corresponding container.  This means updating
        // the item map data structure so that the item belongs to a Realized block.
        // It also requires updating the state of every generator to track the
        // changes we make here.
        void Realize(UnrealizedItemBlock block, int offset, object item, DependencyObject container)
        {
            RealizedItemBlock prevR, nextR;

            RealizedItemBlock newBlock; // new location of the target item
            int newOffset;              // its offset within the new block
            int deltaCount;             // diff between cumulative item count of block and newBlock

            // if we're realizing the leftmost item and there's room in the
            // previous block, move it there
            if (offset == 0 &&
                (prevR = block.Prev as RealizedItemBlock) != null &&
                prevR.ItemCount < ItemBlock.BlockSize)
            {
                newBlock = prevR;
                newOffset = prevR.ItemCount;
                MoveItems(block, offset, 1, newBlock, newOffset, -prevR.ItemCount);
                MoveItems(block, 1, block.ItemCount, block, 0, +1);
            }

            // if we're realizing the rightmost item and there's room in the
            // next block, move it there
            else if (offset == block.ItemCount - 1 &&
                (nextR = block.Next as RealizedItemBlock) != null &&
                nextR.ItemCount < ItemBlock.BlockSize)
            {
                newBlock = nextR;
                newOffset = 0;
                MoveItems(newBlock, 0, newBlock.ItemCount, newBlock, 1, -1);
                MoveItems(block, offset, 1, newBlock, newOffset, offset);
            }

            // otherwise we need a new block for the target item
            else
            {
                newBlock = new RealizedItemBlock();
                newOffset = 0;
                deltaCount = offset;

                // if target is leftmost item, insert it before remaining items
                if (offset == 0)
                {
                    newBlock.InsertBefore(block);
                    MoveItems(block, offset, 1, newBlock, newOffset, 0);
                    MoveItems(block, 1, block.ItemCount, block, 0, +1);
                }

                // if target is rightmost item, insert it after remaining items
                else if (offset == block.ItemCount - 1)
                {
                    newBlock.InsertAfter(block);
                    MoveItems(block, offset, 1, newBlock, newOffset, offset);
                }

                // otherwise split the block into two, with the target in the middle
                else
                {
                    UnrealizedItemBlock newUBlock = new UnrealizedItemBlock();
                    newUBlock.InsertAfter(block);
                    newBlock.InsertAfter(block);
                    MoveItems(block, offset+1, block.ItemCount-offset-1, newUBlock, 0, offset+1);
                    MoveItems(block, offset, 1, newBlock, 0, offset);
                }
            }

            RemoveAndCoalesceBlocksIfNeeded(block);

            // add the new target to the map
            newBlock.RealizeItem(newOffset, item, container);
        }
        // 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));
            } 
        }