internal ItemsChangedEventArgs(NotifyCollectionChangedAction action, GeneratorPosition position, int itemCount, int itemUICount) : this(action, position, new GeneratorPosition(-1, 0), itemCount, itemUICount) { }
internal CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction action, GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList<DependencyObject> removedContainers ) { _action = action; _position = position; _oldPosition = oldPosition; _itemCount = itemCount; _itemUICount = itemUICount; _index = index; _oldIndex = oldIndex; m_removedContainers = removedContainers; }
private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated) { var internalChildren = InternalChildren; var itemContainerGenerator = ItemContainerGenerator; for (var i = internalChildren.Count - 1; i >= 0; i--) { var position = new GeneratorPosition(i, 0); var num2 = itemContainerGenerator.IndexFromGeneratorPosition(position); if ((num2 >= minDesiredGenerated) && (num2 <= maxDesiredGenerated)) continue; itemContainerGenerator.Remove(position, 1); RemoveInternalChildRange(i, 1); } }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ internal ItemsChangedEventArgs(NotifyCollectionChangedAction action, GeneratorPosition position, GeneratorPosition oldPosition, int itemCount, int itemUICount) { _action = action; _position = position; _oldPosition = oldPosition; _itemCount = itemCount; _itemUICount = itemUICount; }
protected override Size MeasureOverride(Size availableSize) { var desiredSize = new Size(); ItemsControl parent = ItemsControl.GetItemsOwner(this); int count = parent != null && parent.HasItems ? parent.Items.Count : 0; // Next line needed otherwise ItemContainerGenerator is null (bug in WinFX ?) UIElementCollection children = InternalChildren; IItemContainerGenerator generator = ItemContainerGenerator; if (count == 0) { generator.RemoveAll(); if (children.Count > 0) RemoveInternalChildRange(0, children.Count); return desiredSize; } // Get the generator position of the first visible data item GeneratorPosition startPos = generator.GeneratorPositionFromIndex(count - 1); using (generator.StartAt(startPos, GeneratorDirection.Forward, true)) { bool newlyRealized; // Get or create the child var child = generator.GenerateNext(out newlyRealized) as UIElement; if (child != null) { if (newlyRealized) { AddInternalChild(child); generator.PrepareItemContainer(child); } child.Measure(availableSize); desiredSize = child.DesiredSize; } } // Remove all other items than the top one for (int i = children.Count - 1; i >= 0; i--) { var childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos); if (itemIndex == count - 1) continue; generator.Remove(childGeneratorPos, 1); RemoveInternalChildRange(i, 1); } return desiredSize; }
// Token: 0x06006113 RID: 24851 RVA: 0x001B3EF4 File Offset: 0x001B20F4 private void MoveChildren(GeneratorPosition fromPos, GeneratorPosition toPos, int containerCount) { if (fromPos == toPos) { return; } IItemContainerGenerator generator = base.Generator; int num = generator.IndexFromGeneratorPosition(toPos); UIElement[] array = new UIElement[containerCount]; for (int i = 0; i < containerCount; i++) { UIElement uielement = this._generatedItemsCollection[fromPos.Index + i]; this.RemoveChild(uielement); array[i] = uielement; } this._generatedItemsCollection.RemoveRange(fromPos.Index, containerCount); for (int j = 0; j < containerCount; j++) { this._generatedItemsCollection.Insert(num + j, array[j]); } }
// THE HACK implementation. A copy from Microsofts VirtualizingStackPanel void RemoveChildRange(GeneratorPosition position, int itemCount, int itemUICount) { if (IsItemsHost) { UIElementCollection children = InternalChildren; int pos = position.Index; if (position.Offset > 0) { // An item is being removed after the one at the index pos++; } if (pos < children.Count) { int uiCount = itemUICount; Debug.Assert((itemCount == itemUICount) || (itemUICount == 0), "Both ItemUICount and ItemCount should be equal or ItemUICount should be 0."); if (uiCount > 0) { RemoveInternalChildRange(pos, uiCount); //VirtualizingPanel.RemoveInternalChildRange(children, pos, uiCount); //if (IsVirtualizing && InRecyclingMode) { //_realizedChildren.RemoveRange(pos, uiCount); //} } } } }
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); } }
void GetBlockAndPosition(object item, bool deletedFromItems, out GeneratorPosition position, out ItemBlock block, out int offsetFromBlockStart, out int correctIndex) { correctIndex = 0; int containerIndex = 0; offsetFromBlockStart = 0; int deletionOffset = deletedFromItems ? 1 : 0; position = new GeneratorPosition(-1, 0); if (_itemMap == null) { // handle reentrant call block = null; return; } for (block = _itemMap.Next; block != _itemMap; block = block.Next) { UnrealizedItemBlock uib; RealizedItemBlock rib = block as RealizedItemBlock; if (rib != null) { // compare realized items with item for which we are searching offsetFromBlockStart = rib.OffsetOfItem(item); if (offsetFromBlockStart >= 0) { position = new GeneratorPosition(containerIndex + offsetFromBlockStart, 0); correctIndex += offsetFromBlockStart; break; } } else if ((uib = block as UnrealizedItemBlock) != null) { // if the item isn't realized, we can't find it // directly. Instead, look for indirect evidence that it // belongs to this block by checking the indices of // nearby realized items. #if DEBUG // Sanity check - make sure data structure is OK so far. rib = block.Prev as RealizedItemBlock; if (rib != null && rib.ContainerCount > 0) { Debug.Assert(Object.Equals(rib.ItemAt(rib.ContainerCount - 1), ItemsInternal[correctIndex - 1]), "Generator data structure is corrupt"); } #endif bool itemIsInCurrentBlock = false; rib = block.Next as RealizedItemBlock; if (rib != null && rib.ContainerCount > 0) { // if the index of the next realized item is off by one, // the deleted item likely comes from the current // unrealized block. itemIsInCurrentBlock = Object.Equals(rib.ItemAt(0), ItemsInternal[correctIndex + block.ItemCount - deletionOffset]); } else if (block.Next == _itemMap) { // similarly if we're at the end of the list and the // overall count is off by one, or if the current block // is the only block, the deleted item likely // comes from the current (last) unrealized block itemIsInCurrentBlock = block.Prev == _itemMap || (ItemsInternal.Count == correctIndex + block.ItemCount - deletionOffset); } if (itemIsInCurrentBlock) { // we don't know where it is in this block, so assume // it's the very first item. offsetFromBlockStart = 0; position = new GeneratorPosition(containerIndex-1, 1); break; } } correctIndex += block.ItemCount; containerIndex += block.ContainerCount; } if (block == _itemMap) { // There's no way of knowing which unrealized block it belonged to, so // the data structure can't be updated correctly. Sound the alarm. throw new InvalidOperationException(SR.Get(SRID.CannotFindRemovedItem)); } }
// 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 GetBlockAndPosition(object item, int itemIndex, bool deletedFromItems, out GeneratorPosition position, out ItemBlock block, out int offsetFromBlockStart, out int correctIndex) { if (itemIndex >= 0) { GetBlockAndPosition(itemIndex, out position, out block, out offsetFromBlockStart); correctIndex = itemIndex; } else { GetBlockAndPosition(item, deletedFromItems, out position, out block, out offsetFromBlockStart, out correctIndex); } }
void GetBlockAndPosition(int itemIndex, out GeneratorPosition position, out ItemBlock block, out int offsetFromBlockStart) { position = new GeneratorPosition(-1, 0); block = null; offsetFromBlockStart = itemIndex; if (_itemMap == null || itemIndex < 0) return; int containerIndex = 0; for (block = _itemMap.Next; block != _itemMap; block = block.Next) { if (offsetFromBlockStart >= block.ItemCount) { // item belongs to a later block, increment the containerIndex containerIndex += block.ContainerCount; offsetFromBlockStart -= block.ItemCount; } else { // item belongs to this block. Determine the container index and offset if (block.ContainerCount > 0) { // block has realized items position = new GeneratorPosition(containerIndex + offsetFromBlockStart, 0); } else { // block has unrealized items position = new GeneratorPosition(containerIndex-1, offsetFromBlockStart+1); } break; } } }
// Called when the items collection is refreshed void OnRefresh() { ((IItemContainerGenerator)this).RemoveAll(); // tell layout what happened if (ItemsChanged != null) { GeneratorPosition position = new GeneratorPosition(0, 0); ItemsChanged(this, new ItemsChangedEventArgs(NotifyCollectionChangedAction.Reset, position, 0, 0)); } }
private GeneratorPosition FindPreviousUnrealizedGeneratorPosition( GeneratorPosition position ) { int index = this.IndexFromGeneratorPosition( position ) - 1; while( index >= 0 ) { if( !m_genPosToIndex.Contains( index ) ) { break; } index--; } GeneratorPosition retval = this.GeneratorPositionFromIndex( index ); return retval; }
/// <summary> /// Arrange Override /// </summary> protected override Size ArrangeOverride(Size finalSize) { // monitors changes to the ScrollViewer extent value if (_oldExtent != _extent) { _oldExtent = _extent; if (_scrollOwner != null) _scrollOwner.InvalidateScrollInfo(); } // monitors changes to the parent container size, (ie window resizes) if (finalSize != _lastSize) { _lastSize = finalSize; if (_scrollOwner != null) _scrollOwner.InvalidateScrollInfo(); } // monitor scrolling being removed bool invalidateMeasure = false; if (_extent.Width <= _viewPort.Width && _offset.X > 0) { _offset.X = 0; _translateTransform.X = 0; if (_scrollOwner != null) _scrollOwner.InvalidateScrollInfo(); invalidateMeasure = true; } if (_extent.Height <= _viewPort.Height && _offset.Y > 0) { _offset.Y = 0; _translateTransform.Y = 0; if (_scrollOwner != null) _scrollOwner.InvalidateScrollInfo(); invalidateMeasure = true; } if (invalidateMeasure) InvalidateMeasure(); // arrange the children double leftOrTop = 0; for (int i = 0; i < InternalChildren.Count; i++) { UIElement child = InternalChildren[i]; GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = this.ItemContainerGenerator.IndexFromGeneratorPosition(childGeneratorPos); child.Arrange(_childRects[itemIndex]); leftOrTop += (_tabStripPlacement == Dock.Top || _tabStripPlacement == Dock.Bottom) ? _childRects[i].Width : _childRects[i].Height; } // we need these lines as when the Scroll Buttons get Shown/Hidden, // the _offset value gets out of line, this will ensure that our scroll position stays in line if (InternalChildren.Count > 0) { _offset = _childRects[FirstVisibleIndex].TopLeft; _translateTransform.X = -_offset.X; _translateTransform.Y = -_offset.Y; } return finalSize; }
protected override Size MeasureOverride(Size availableSize) { Size desiredSize = new Size(); UIElementCollection children = InternalChildren; IItemContainerGenerator generator = ItemContainerGenerator; int itemsCount = 0; if (generator != null) { int StartItemIndex = navigationPane.GetFirstItemIndex(DisplayType); if (StartItemIndex > -1) { int maxItems = DisplayType == NavigationPaneItemDisplayType.Large ? navigationPane.LargeItems : int.MaxValue; GeneratorPosition startPos = new GeneratorPosition(-1, StartItemIndex + 1); using (generator.StartAt(startPos, GeneratorDirection.Forward, true)) { bool sizeExceeded = false; bool newlyRealized; UIElement child = null; // temp fix for {Disconnected Item} // needs more inspecting and documentation to fix it correctly !! // but this for now seems to work... strange items present ?? // remove them, NOW !!!!! //for (int j = children.Count - 1; j > -1; j--) //{ //UIElement item = children[j]; //object o = navigationPane.ItemContainerGenerator.ItemFromContainer(item); //if (o == DependencyProperty.UnsetValue) // RemoveInternalChild(item); //} while (!sizeExceeded && (itemsCount < maxItems) && (child = generator.GenerateNext(out newlyRealized) as UIElement) != null) { bool isExcluded = NavigationPane.GetIsItemExcluded(child); if (!isExcluded) { if (newlyRealized || !children.Contains(child)) { int absoluteIndex = StartItemIndex + itemsCount; int index = GetInsertIndex(absoluteIndex); if (absoluteIndex < 9 && navigationPane.ItemsKeyAuto) { NavigationPaneItem f = child as NavigationPaneItem; { Window w = Window.GetWindow(child); if (w != null) { KeyBinding binding = f.keyBinding; if (binding != null) w.InputBindings.Remove(binding); f.keyBinding = new KeyBinding(NavigationPane.SelectItemCommand, Key.D1 + absoluteIndex, navigationPane.ItemsKeyModifiers); f.keyBinding.CommandParameter = child; f.keyBinding.CommandTarget = navigationPane; w.InputBindings.Add(f.keyBinding); if (f != null) f.Gesture = (f.keyBinding.Gesture as KeyGesture).GetDisplayStringForCulture(CultureInfo.CurrentCulture); } } } SetActivePanel(child, this); SetAbosluteIndex(child, absoluteIndex); SetItemDisplayType(child, DisplayType); if (newlyRealized) generator.PrepareItemContainer(child); InsertInternalChild(index, child); } #region measurament algoritm Size childSize = new Size(); if (Orientation == Orientation.Vertical) childSize = new Size(availableSize.Width, double.PositiveInfinity); else childSize = new Size(double.PositiveInfinity, availableSize.Height); child.Measure(childSize); if (Orientation == Orientation.Vertical) { sizeExceeded = desiredSize.Height + child.DesiredSize.Height > availableSize.Height; if (!sizeExceeded) { desiredSize.Width = Math.Max(desiredSize.Width, child.DesiredSize.Width); desiredSize.Height += child.DesiredSize.Height; } } else { sizeExceeded = desiredSize.Width + child.DesiredSize.Width > availableSize.Width; if (!sizeExceeded) { desiredSize.Width += child.DesiredSize.Width; desiredSize.Height = Math.Max(desiredSize.Height, child.DesiredSize.Height); } } #endregion if (!sizeExceeded) itemsCount++; } else { RemoveInternalChild(child); } } } CleanUpItems(StartItemIndex, itemsCount); } } if(DisplayType == NavigationPaneItemDisplayType.Small) navigationPane.SmallItems = itemsCount; return desiredSize; }
public CustomItemContainerGeneratorDisposableDisposer( CustomItemContainerGenerator generator, GeneratorPosition startGenPos, GeneratorDirection direction ) { if( generator == null ) { throw new ArgumentNullException( "generator" ); } m_generator = generator; m_generator.StartGenerator( startGenPos, direction ); }
private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated) { var generator = ItemContainerGenerator; for (var i = InternalChildren.Count - 1; i >= 0; i--) { var childGeneratorPos = new GeneratorPosition(i, 0); var itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos); if (itemIndex < minDesiredGenerated || itemIndex > maxDesiredGenerated) { RemoveInternalChildRange(i, 1); generator.Remove(childGeneratorPos, 1); } } }
private GeneratorPosition ConvertDetailGeneratorPosition( GeneratorPosition referencePosition, object masterItem, DetailGeneratorNode detailNode, out int globalIndex ) { //If the requested generator position map past at least one generated item from the detail generator, then the job is easy... if( referencePosition.Index >= 0 ) { int generatorIndex = this.FindGeneratorIndexForNode( detailNode, referencePosition.Index ); // Ensure to return the globalIndex as -1 // if the generator index is not found for // a DetailNode. This can occur if a Detail // is filtered out via AutoFiltering. globalIndex = ( generatorIndex > -1 ) ? m_genPosToIndex[ generatorIndex ] : globalIndex = -1; return new GeneratorPosition( generatorIndex, referencePosition.Offset ); } else { //This means the GeneratorPosition returned by the DetailGenerator is "before" any generated item from the detail generator. //I need more complex detection of the GeneratorPosition. // First - Get the Index of the MasterItem int masterIndex = this.IndexFromItem( masterItem ); //Second - Get the DetailGenerator's Index for the DetailGenerator's GenPos int detailGeneratorIndex = detailNode.DetailGenerator.IndexFromGeneratorPosition( referencePosition ); globalIndex = masterIndex + detailGeneratorIndex + 1; // Finally - Have the Master Generator compute the GeneratorPosition from the sum of both return this.GeneratorPositionFromIndex( globalIndex ); } }
private void RemoveDetailContainers( GeneratorPosition convertedGeneratorPosition, int removeCount ) { int removeGenPosIndex = convertedGeneratorPosition.Index; if( convertedGeneratorPosition.Offset > 0 ) { removeGenPosIndex++; } for( int i = 0; i < removeCount; i++ ) { this.GenPosArraysRemoveAt( removeGenPosIndex ); } }
private void HandleDetailReset( object masterItem, DetailGeneratorNode detailNode ) { GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); int masterIndex = nodeHelper.FindItem( masterItem ); // -1 means either taht the master item is below a collapsed group node, or that the item does not exists, validate. if( masterIndex == -1 ) { nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); if( !nodeHelper.Contains( masterItem ) ) throw new DataGridInternalException(); } ItemsGeneratorNode masterNode = nodeHelper.CurrentNode as ItemsGeneratorNode; Debug.Assert( masterNode != null, "masterNode != null" ); #if LOG Log.Assert( this, masterNode != null, "masterNode != null" ); #endif //start index will be ignored later on if the masterIndex is -1!! int startIndex = nodeHelper.Index + masterNode.IndexOf( masterItem ) + 1; //details start a master index + 1 List<DetailGeneratorNode> detailsForMaster = null; //edge case, it is possible to receive a Reset from Floating details! if( masterNode.Details == null ) { //check for floating details, if not present, throw, this is an abnormal case. if( !m_floatingDetails.Contains( masterItem ) ) { throw new DataGridInternalException(); } } else { masterNode.Details.TryGetValue( masterNode.Items.IndexOf( masterItem ), out detailsForMaster ); Debug.Assert( detailsForMaster != null, "detailsForMaster != null" ); #if LOG Log.Assert( this, detailsForMaster != null, "detailsForMaster != null" ); #endif } if( detailsForMaster != null ) { //this is required to ensure that if the details that resets is not the first one, the index is calculated appropriatly. foreach( DetailGeneratorNode node in detailsForMaster ) { if( node == detailNode ) { break; } else { startIndex += node.ItemCount; } } //if there were 'items' in the detail node, process the remove of them int oldDetailCount = detailNode.ItemCount; if( oldDetailCount > 0 ) { int endIndex = startIndex + oldDetailCount - 1; //last detail index GeneratorPosition removeGenPos = ( masterIndex != -1 ) ? this.GeneratorPositionFromIndex( startIndex ) : new GeneratorPosition( -1, 1 ); int genRemCount = 0; List<DependencyObject> removedContainers = new List<DependencyObject>(); //this has no uses if the masterIndex is -1 ( collapsed master item ) if( masterIndex != -1 ) { genRemCount = this.RemoveGeneratedItems( startIndex, endIndex, removedContainers ); } masterNode.AdjustItemCount( -oldDetailCount ); this.IncrementCurrentGenerationCount(); //this has no uses if the masterIndex is -1 ( collapsed master item ) if( masterIndex != -1 ) { this.SendRemoveEvent( removeGenPos, masterIndex + 1, oldDetailCount, genRemCount, removedContainers ); } } detailNode.UpdateItemCount(); int newDetailCount = detailNode.ItemCount; if( newDetailCount > 0 ) { GeneratorPosition addGenPos = new GeneratorPosition( -1, 1 ); //this has no uses if the masterIndex is -1 ( collapsed master item ) if( masterIndex != -1 ) { addGenPos = this.GeneratorPositionFromIndex( startIndex ); } masterNode.AdjustItemCount( newDetailCount ); this.IncrementCurrentGenerationCount(); //this has no uses if the masterIndex is -1 ( collapsed master item ) if( masterIndex != -1 ) { this.SendAddEvent( addGenPos, masterIndex + 1, newDetailCount ); } } } }
/// <summary> /// Remove generated elements. /// </summary> void IItemContainerGenerator.Remove(GeneratorPosition position, int count) { Remove(position, count, /*isRecycling = */ false); }
/// <summary> /// Map a GeneratorPosition to an index into the items collection. /// </summary> int IItemContainerGenerator.IndexFromGeneratorPosition(GeneratorPosition position) { int index = position.Index; if (index == -1) { // offset is relative to the fictitious boundary item if (position.Offset >= 0) { return position.Offset - 1; } else { return ItemsInternal.Count + position.Offset; } } if (_itemMap != null) { int itemIndex = 0; // number of items we've skipped over // locate container at the given index for (ItemBlock block = _itemMap.Next; block != _itemMap; block = block.Next) { if (index < block.ContainerCount) { // container is within this block. return the answer return itemIndex + index + position.Offset; } else { // skip over this block itemIndex += block.ItemCount; index -= block.ContainerCount; } } } return -1; }
/// <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); }
// Token: 0x06005E4F RID: 24143 RVA: 0x001A7404 File Offset: 0x001A5604 internal ItemsChangedEventArgs(NotifyCollectionChangedAction action, GeneratorPosition position, GeneratorPosition oldPosition, int itemCount, int itemUICount) { this._action = action; this._position = position; this._oldPosition = oldPosition; this._itemCount = itemCount; this._itemUICount = itemUICount; }
void IRecyclingItemContainerGenerator.Recycle(GeneratorPosition position, int count) { Remove(position, count, /*isRecyling = */ true); }
// Token: 0x06005E50 RID: 24144 RVA: 0x001A7431 File Offset: 0x001A5631 internal ItemsChangedEventArgs(NotifyCollectionChangedAction action, GeneratorPosition position, int itemCount, int itemUICount) : this(action, position, new GeneratorPosition(-1, 0), itemCount, itemUICount) { }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ internal Generator(ItemContainerGenerator factory, GeneratorPosition position, GeneratorDirection direction, bool allowStartAtRealizedItem) { _factory = factory; _direction = direction; _factory.MapChanged += new MapChangedHandler(OnMapChanged); _factory.MoveToPosition(position, direction, allowStartAtRealizedItem, ref _cachedState); _done = (_factory.ItemsInternal.Count == 0); _factory.SetStatus(GeneratorStatus.GeneratingContainers); }
/// <summary> Begin generating at the given position and direction </summary> /// <remarks> /// This method must be called before calling GenerateNext. It returns an /// IDisposable object that tracks the lifetime of the generation loop. /// This method sets the generator's status to GeneratingContent; when /// the IDisposable is disposed, the status changes to ContentReady or /// Error, as appropriate. /// </remarks> IDisposable IItemContainerGenerator.StartAt(GeneratorPosition position, GeneratorDirection direction, bool allowStartAtRealizedItem) { if (_generator != null) throw new InvalidOperationException(SR.Get(SRID.GenerationInProgress)); _generator = new Generator(this, position, direction, allowStartAtRealizedItem); return _generator; }
/// <summary> /// Virtualize hidden items /// </summary> private void CleanUpItems() { try { UIElementCollection children = this.InternalChildren; IItemContainerGenerator generator = this.ItemContainerGenerator; for (int i = children.Count - 1; i >= 0; i--) { GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos); if (itemIndex == -1) continue; if (itemIndex < FirstVisibleIndex || itemIndex > LastVisibleIndex) { generator.Remove(childGeneratorPos, 1); RemoveInternalChildRange(i, 1); } } } catch (Exception ex) { VMuktiAPI.VMuktiHelper.ExceptionHandler(ex, "CleanUpItems()", "Controls\\VMuktiGrid\\Page\\VirtualizingTabPanel.cs"); } }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ void MoveToPosition(GeneratorPosition position, GeneratorDirection direction, bool allowStartAtRealizedItem, ref GeneratorState state) { ItemBlock block = _itemMap; if (block == null) return; // this can happen in event-leapfrogging situations (Dev11 283413) int itemIndex = 0; // first move to the indexed (realized) item if (position.Index != -1) { // find the right block int itemCount = 0; int index = position.Index; block = block.Next; while (index >= block.ContainerCount) { itemCount += block.ItemCount; index -= block.ContainerCount; itemIndex += block.ItemCount; block = block.Next; } // set the position state.Block = block; state.Offset = index; state.Count = itemCount; state.ItemIndex = itemIndex + index; } else { state.Block = block; state.Offset = 0; state.Count = 0; state.ItemIndex = itemIndex - 1; } // adjust the offset - we always set the state so it points to the next // item to be generated. int offset = position.Offset; if (offset == 0 && (!allowStartAtRealizedItem || state.Block == _itemMap)) { offset = (direction == GeneratorDirection.Forward) ? 1 : -1; } // advance the state according to the offset if (offset > 0) { state.Block.MoveForward(ref state, true); -- offset; while (offset > 0) { offset -= state.Block.MoveForward(ref state, allowStartAtRealizedItem, offset); } } else if (offset < 0) { if (state.Block == _itemMap) { state.ItemIndex = state.Count = ItemsInternal.Count; } state.Block.MoveBackward(ref state, true); ++ offset; while (offset < 0) { offset += state.Block.MoveBackward(ref state, allowStartAtRealizedItem, -offset); } } }
private void CleanUpItems(int StartItemIndex, int itemsCount) { UIElementCollection children = InternalChildren; IItemContainerGenerator generator = ItemContainerGenerator; int first = StartItemIndex; int last = StartItemIndex + itemsCount - 1; for (int i = children.Count - 1; i >= 0; i--) { // Map a child index to an item index by going through a generator position GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos); itemIndex = i + StartItemIndex; if (itemIndex < first || itemIndex > last) { //generator.Remove(childGeneratorPos, 1); //generator.Remove(new GeneratorPosition(itemIndex, 0), 1); RemoveInternalChildRange(i, 1); } } }
/// <summary> Begin generating at the given position and direction </summary> /// <remarks> /// This method must be called before calling GenerateNext. It returns an /// IDisposable object that tracks the lifetime of the generation loop. /// This method sets the generator's status to GeneratingContent; when /// the IDisposable is disposed, the status changes to ContentReady or /// Error, as appropriate. /// </remarks> IDisposable IItemContainerGenerator.StartAt(GeneratorPosition position, GeneratorDirection direction) { return ((IItemContainerGenerator)this).StartAt(position, direction, false); }