protected CollectionGeneratorNode( IList list, GeneratorNode parent ) : base( parent ) { Debug.Assert( list != null, "list cannot be null for CollectionGeneratorNode" ); m_items = list; }
public GroupGeneratorNode( CollectionViewGroup group, GeneratorNode parent, GroupConfiguration groupConfig ) : base( parent ) { Debug.Assert( group != null, "group cannot be null for GroupGeneratorNode" ); Debug.Assert( groupConfig != null ); m_group = group; m_groupConfig = groupConfig; }
public GeneratorNodeHelper( GeneratorNode initialPointer, int index, int sourceDataIndex ) { if( initialPointer == null ) throw new ArgumentNullException( "initialPointer" ); m_currentNode = initialPointer; m_index = index; m_sourceDataIndex = sourceDataIndex; }
private readonly WeakReference m_dataGridControl; //null #endregion public GeneratorNode CreateGroupGeneratorNode( CollectionViewGroup collectionViewGroup, GeneratorNode parent, GeneratorNode previous, GeneratorNode next, GroupConfiguration groupConfig ) { Debug.Assert( collectionViewGroup != null, "collectionViewGroup cannot be null for CreateGroupGeneratorNode()" ); GroupGeneratorNode node = new GroupGeneratorNode( collectionViewGroup, parent, groupConfig ); if( previous != null ) { previous.Next = node; } node.Previous = previous; if( next != null ) { next.Previous = node; } node.Next = next; node.IsExpanded = groupConfig.InitiallyExpanded; if( !collectionViewGroup.IsBottomLevel ) { this.RegisterNodeCollectionChanged( ( INotifyCollectionChanged )collectionViewGroup.GetItems(), new NotifyCollectionChangedEventHandler( node.OnCollectionChanged ) ); node.CollectionChanged += m_groupsChangedHandler; } node.ExpansionStateChanged += m_expansionStateChangedHandler; node.IsExpandedChanging += m_isExpandedChangingHandler; node.IsExpandedChanged += m_isExpandedChangedHandler; node.AdjustItemCount( node.ItemCount ); node.BuildNamesTree(); return node; }
public void CleanGeneratorNode(GeneratorNode node) { HeadersFootersGeneratorNode headersFootersNode = node as HeadersFootersGeneratorNode; if (headersFootersNode != null) { this.CleanHeadersFootersNotification(headersFootersNode); } else { ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; if (itemsNode != null) { this.UnregisterNodeCollectionChanged(( INotifyCollectionChanged )itemsNode.Items); itemsNode.CollectionChanged -= m_itemsChangedHandler; } else { GroupGeneratorNode groupNode = node as GroupGeneratorNode; if (groupNode != null) { IList <object> subItems = groupNode.CollectionViewGroup.GetItems(); this.UnregisterNodeCollectionChanged(( INotifyCollectionChanged )subItems); groupNode.CollectionChanged -= m_groupsChangedHandler; groupNode.IsExpandedChanging -= m_isExpandedChangingHandler; groupNode.IsExpandedChanged -= m_isExpandedChangedHandler; } } } node.ExpansionStateChanged -= m_expansionStateChangedHandler; node.CleanGeneratorNode(); }
private DependencyObject CreateContainerForItem( object dataItem, GeneratorNode node ) { DependencyObject retval = null; if( node is HeadersFootersGeneratorNode ) { retval = this.CreateHeaderFooterContainer( dataItem ); if( node.Parent == null ) { GroupLevelIndicatorPane.SetGroupLevel( retval, -1 ); } else { GroupLevelIndicatorPane.SetGroupLevel( retval, node.Level ); } this.SetStatContext( retval, node ); } else if( node is ItemsGeneratorNode ) { //ensure that item is not its own container... if( !this.IsItemItsOwnContainer( dataItem ) ) { retval = this.CreateNextItemContainer(); } else { retval = dataItem as DependencyObject; } GroupLevelIndicatorPane.SetGroupLevel( retval, node.Level ); } else { throw new DataGridInternalException(); } if( retval == null ) { throw new DataGridInternalException(); } CustomItemContainerGenerator.SetDataItemProperty( retval, dataItem ); DataGridControl.SetDataGridContext( retval, m_dataGridContext ); return retval; }
private void HandleItemReset( GeneratorNode node ) { //these 4 variables will hold the content for the Removal and the re-addition of the items. int countGeneratedRemoved; GeneratorPosition itemGenPos; List<DependencyObject> removedContainers = new List<DependencyObject>(); //by definition, items from a node are contiguous... itemGenPos = this.FindFirstRealizedItemsForNode( node ); int removeIndex = ( itemGenPos.Offset == 0 ) ? m_genPosToIndex[ itemGenPos.Index ] : -1; countGeneratedRemoved = this.RemoveGeneratedItems( node, removedContainers ); // ensure that the mapping of the details to that node are removed! ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; if( ( itemsNode != null ) && ( itemsNode.Details != null ) ) { int detailCount = 0; foreach( List<DetailGeneratorNode> detailList in itemsNode.Details.Values ) { foreach( DetailGeneratorNode detailNode in detailList ) { detailCount += detailNode.ItemCount; } } #if LOG Log.WriteLine( this, "details.Clear - IN" + itemsNode.GetHashCode().ToString() ); #endif itemsNode.Details.Clear(); itemsNode.Details = null; node.AdjustItemCount( -detailCount ); } //send the removal notification to the panel... this.IncrementCurrentGenerationCount(); if( countGeneratedRemoved > 0 ) { this.SendRemoveEvent( itemGenPos, removeIndex, 0, countGeneratedRemoved, removedContainers ); } }
private GeneratorNode HandleParentGroupAddition( GeneratorNode parent, out int countAdded, NotifyCollectionChangedEventArgs e ) { GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). //start by moving to the first child... of the node (GroupHeaders node, most probably). if( !nodeHelper.MoveToChild( false ) ) //case 120137: false parameter is to prevent skipping over a collapsed node (item count 0 ) { //could not advance to the child item so there is no items to be removed... throw new DataGridInternalException(); } return this.HandleSameLevelGroupAddition( nodeHelper.CurrentNode, out countAdded, e ); }
private void HandleSameLevelGroupMove( GeneratorNode node, NotifyCollectionChangedEventArgs e ) { GroupGeneratorNode parentGroup = node.Parent as GroupGeneratorNode; //Start a NodeHelper on the first child of the node where the move occured. GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); nodeHelper.ReverseCalculateIndex(); //determine index of the node. //Advance to the first "Group" node (skip the GroupHEaders) while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) { if( !nodeHelper.MoveToNext() ) throw new DataGridInternalException(); } //then move up to the removal start point. if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) { throw new DataGridInternalException(); } //remember the current node as the start point of the move (will be used when "extracting the chain") GeneratorNode startNode = nodeHelper.CurrentNode; //also remember the index of the node, to calculate range of elements to remove (containers ) int startIndex = nodeHelper.Index; //then, cumulate the total number of items in the groups concerned int totalCountRemoved = 0; node = this.ProcessGroupRemoval( startNode, e.OldItems.Count, false, out totalCountRemoved ); //send a message to the panel to remove the visual elements concerned GeneratorPosition removeGenPos = this.GeneratorPositionFromIndex( startIndex ); List<DependencyObject> removedContainers = new List<DependencyObject>(); int genCountRemoved = this.RemoveGeneratedItems( startIndex, startIndex + totalCountRemoved - 1, removedContainers ); this.SendRemoveEvent( removeGenPos, startIndex, totalCountRemoved, genCountRemoved, removedContainers ); //reset the node parameter for the "re-addition" node = ( parentGroup != null ) ? parentGroup.Child : m_firstItem; if( node == null ) throw new DataGridInternalException(); //Once the chain was pulled out, re-insert it at the appropriate location. nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //do not care about the index for what I need //Advance to the first "Group" node (skip the GroupHEaders) while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) { if( !nodeHelper.MoveToNext() ) throw new DataGridInternalException(); } bool insertBefore = nodeHelper.MoveToNextBy( e.NewStartingIndex ); if( insertBefore ) { if( nodeHelper.CurrentNode == m_firstItem ) { if( m_startNode == m_firstItem ) { m_startNode = startNode; } m_firstItem = startNode; } //reinsert the chain at the specified location. nodeHelper.InsertBefore( startNode ); } else { nodeHelper.InsertAfter( startNode ); } //and finally, call to increment the generation count for the generator content this.IncrementCurrentGenerationCount(); }
public static GeneratorNode EvaluateChain( GeneratorNode chainStart, out int totalChildCount, out int chainLength ) { //if we insert a chain of nodes, this GeneratorNodeHelper will help us GeneratorNodeHelper newHelper = new GeneratorNodeHelper( chainStart, 0, 0 ); //first determine the total number of childs from this "node" totalChildCount = 0; chainLength = 0; do { totalChildCount += newHelper.CurrentNode.ItemCount; chainLength++; } while( newHelper.MoveToNext() ); //then, since we moved at the end of the "chain" return newHelper.CurrentNode; }
public bool InsertAfter( GeneratorNode insert ) { if( insert == null ) throw new DataGridInternalException( "GeneratorNode is null." ); int insertionCount; int chainLength; GeneratorNode insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); if( m_currentNode.Next != null ) { m_currentNode.Next.Previous = insertLast; } insertLast.Next = m_currentNode.Next; insert.Previous = m_currentNode; m_currentNode.Next = insert; // Move the current node to the last node inserted if( !this.MoveToNextBy( chainLength ) ) throw new DataGridInternalException( "Unable to move to the requested generator index." ); return true; }
public ItemsGeneratorNode(IList list, GeneratorNode parent) : base(list, parent) { }
private void SetupCollectionGeneratorNode( CollectionGeneratorNode newNode, GeneratorNode parent, GeneratorNode previous, GeneratorNode next ) { if( previous != null ) { previous.Next = newNode; } newNode.Previous = previous; if( next != null ) { next.Previous = newNode; } newNode.Next = next; this.RegisterNodeCollectionChanged( ( INotifyCollectionChanged )newNode.Items, new NotifyCollectionChangedEventHandler( newNode.OnCollectionChanged ) ); newNode.CollectionChanged += m_itemsChangedHandler; newNode.ExpansionStateChanged += m_expansionStateChangedHandler; if( parent != null ) { newNode.AdjustItemCount( newNode.ItemCount ); } }
public void CleanGeneratorNode( GeneratorNode node ) { HeadersFootersGeneratorNode headersFootersNode = node as HeadersFootersGeneratorNode; if( headersFootersNode != null ) { this.CleanHeadersFootersNotification( headersFootersNode ); } else { ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; if( itemsNode != null ) { this.UnregisterNodeCollectionChanged( ( INotifyCollectionChanged )itemsNode.Items ); itemsNode.CollectionChanged -= m_itemsChangedHandler; } else { GroupGeneratorNode groupNode = node as GroupGeneratorNode; if( groupNode != null ) { IList<object> subItems = groupNode.CollectionViewGroup.GetItems(); this.UnregisterNodeCollectionChanged( ( INotifyCollectionChanged )subItems ); groupNode.CollectionChanged -= m_groupsChangedHandler; groupNode.IsExpandedChanging -= m_isExpandedChangingHandler; groupNode.IsExpandedChanged -= m_isExpandedChangedHandler; } } } node.ExpansionStateChanged -= m_expansionStateChangedHandler; node.CleanGeneratorNode(); }
public void CleanGeneratorNodeTree( GeneratorNode node ) { if( node.Parent != null ) { node.Parent.AdjustItemCount( -node.ItemCount ); GroupGeneratorNode parentGroupNode = node.Parent as GroupGeneratorNode; if( ( parentGroupNode != null ) && ( parentGroupNode.Child == node ) ) { parentGroupNode.Child = null; } } GeneratorNode child; GeneratorNode next; do { GroupGeneratorNode groupNode = node as GroupGeneratorNode; next = node.Next; child = ( groupNode != null ) ? groupNode.Child : null; this.CleanGeneratorNode( node ); //this recursive function cleans up the tree of nodes if( child != null ) { this.CleanGeneratorNodeTree( child ); } node = next; } while( node != null ); }
public HeadersFootersGeneratorNode CreateHeadersFootersGeneratorNode( IList collection, GeneratorNode parent, GeneratorNode previous, GeneratorNode next ) { Debug.Assert( collection != null, "collection cannot be null for CreateHeadersFootersGeneratorNode()" ); INotifyCollectionChanged notifyCollection = collection as INotifyCollectionChanged; Debug.Assert( notifyCollection != null, "collection must be a INotifyCollectionChanged for CreateHeadersFootersGeneratorNode()" ); HeadersFootersGeneratorNode node = new HeadersFootersGeneratorNode( collection, parent ); if( previous != null ) { previous.Next = node; } node.Previous = previous; if( next != null ) { next.Previous = node; } node.Next = next; node.ExpansionStateChanged += m_expansionStateChangedHandler; this.ConfigureHeadersFootersNotification( notifyCollection, node ); if( parent != null ) { node.AdjustItemCount( node.ItemCount ); } return node; }
public GeneratorNode CreateItemsGeneratorNode( IList collection, GeneratorNode parent, GeneratorNode previous, GeneratorNode next, CustomItemContainerGenerator generator ) { Debug.Assert( collection != null, "collection cannot be null for CreateItemsGeneratorNode()" ); Debug.Assert( generator != null ); INotifyCollectionChanged notifyCollection = collection as INotifyCollectionChanged; Debug.Assert( notifyCollection != null, "collection must be a INotifyCollectionChanged for CreateItemsGeneratorNode()" ); ItemCollection itemCollection = collection as ItemCollection; if( itemCollection != null ) { DataGridCollectionView dgcv = itemCollection.SourceCollection as DataGridCollectionView; if( dgcv != null ) { collection = dgcv; } } ItemsGeneratorNode node = new ItemsGeneratorNode( collection, parent ); this.SetupCollectionGeneratorNode( node, parent, previous, next ); node.AdjustLeafCount( node.Items.Count ); return node; }
public ItemsGeneratorNode( IList list, GeneratorNode parent ) : base( list, parent ) { }
private int RemoveGeneratedItems( GeneratorNode referenceNode, IList<DependencyObject> removedContainers ) { int genCountRemoved = 0; List<GeneratorNode> toRemove = new List<GeneratorNode>(); toRemove.Add( referenceNode ); ItemsGeneratorNode itemsNode = referenceNode as ItemsGeneratorNode; if( itemsNode != null ) { if( itemsNode.Details != null ) { //cycle through all the details currently mapped to the reference node foreach( KeyValuePair<int, List<DetailGeneratorNode>> detailsForNode in itemsNode.Details ) { foreach( DetailGeneratorNode detailNode in detailsForNode.Value ) { toRemove.Add( detailNode ); } } } } //cycle through the list of generated items, and see if any items are from the reference node passed. //start from the end so that removing an item will not cause the indexes to shift for( int i = m_genPosToNode.Count - 1; i >= 0; i-- ) { GeneratorNode node = m_genPosToNode[ i ]; //if the item is within the range removed if( toRemove.Contains( node ) ) { //this will ensure to recurse the call to the appropriate Detail Generator for clearing of the container. //otherwise, it will only remove it from the list of container generated in the current generator instance. this.RemoveGeneratedItem( i, removedContainers ); //increment realized item count removed genCountRemoved++; } } return genCountRemoved; }
//FindItem skips over itemless nodes. public int FindItem(object item) { //finding items can only be done in "forward" direction int retval = -1; GeneratorNode originalNode = m_currentNode; int originalIndex = m_index; int originalSourceDataIndex = m_sourceDataIndex; while (retval == -1) { ItemsGeneratorNode itemsNode = m_currentNode as ItemsGeneratorNode; if (itemsNode != null) { int tmpIndex = itemsNode.Items.IndexOf(item); if (tmpIndex > -1) { tmpIndex += itemsNode.CountDetailsBeforeDataIndex(tmpIndex); //item is directly from this items node... then return the appropriate index! retval = m_index + tmpIndex; break; } else { //if the item is from a detail, then I don't want to "use" it!!! retval = -1; //but continue looping.... to find occurances of this item somewhere else in the tree } } else { CollectionGeneratorNode collectionNode = m_currentNode as CollectionGeneratorNode; if (collectionNode != null) { int tmpIndex = collectionNode.IndexOf(item); if (tmpIndex != -1) { retval = m_index + tmpIndex; break; } } } //if we reach this point, it's because the item we are looking //for is not in this node... Try to access the child if (this.MoveToChild()) { continue; } //if we reach this point, it's because we have no child... if (this.MoveToNext()) { continue; } //final try, try "advancing" to the next item. if (this.MoveToFollowing()) { continue; } //up to this, we are in an endpoint, we failed. break; } if (retval == -1) { m_currentNode = originalNode; m_index = originalIndex; m_sourceDataIndex = originalSourceDataIndex; } return(retval); }
private GeneratorNode SetupGroupHeaders( GroupConfiguration groupConfig, GeneratorNode actualNode ) { if( groupConfig == null ) { return new GeneratorNode( actualNode ); } return this.NodeFactory.CreateHeadersFootersGeneratorNode( groupConfig.Headers, actualNode, null, null ); }
private void SetupCollectionGeneratorNode(CollectionGeneratorNode newNode, GeneratorNode parent, GeneratorNode previous, GeneratorNode next) { if (previous != null) { previous.Next = newNode; } newNode.Previous = previous; if (next != null) { next.Previous = newNode; } newNode.Next = next; this.RegisterNodeCollectionChanged(( INotifyCollectionChanged )newNode.Items, new NotifyCollectionChangedEventHandler(newNode.OnCollectionChanged)); newNode.CollectionChanged += m_itemsChangedHandler; newNode.ExpansionStateChanged += m_expansionStateChangedHandler; if (parent != null) { newNode.AdjustItemCount(newNode.ItemCount); } }
private GeneratorPosition HandleSameLevelGroupRemove( GeneratorNode firstChild, out int countRemoved, out int genCountRemoved, out int removeIndex, NotifyCollectionChangedEventArgs e, IList<DependencyObject> removedContainers ) { GeneratorPosition retval; countRemoved = 0; genCountRemoved = 0; GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); nodeHelper.ReverseCalculateIndex(); //Advance to the first "Group" node (skip the GroupHEaders) while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) { if( !nodeHelper.MoveToNext() ) throw new DataGridInternalException(); } //then move up to the removal start point. if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) { throw new DataGridInternalException(); } GroupGeneratorNode startNode = nodeHelper.CurrentNode as GroupGeneratorNode; removeIndex = -1; //Only fetch the index if the group itself is not "collapsed" or under a collapsed group already if( ( startNode.IsExpanded == startNode.IsComputedExpanded ) && ( startNode.ItemCount > 0 ) ) { removeIndex = nodeHelper.Index; retval = this.GeneratorPositionFromIndex( removeIndex ); } else { retval = new GeneratorPosition( -1, 1 ); } //retrieve the generator position for the first item to remove. this.ProcessGroupRemoval( startNode, e.OldItems.Count, true, out countRemoved ); //Clean the chain "isolated" previously this.NodeFactory.CleanGeneratorNodeTree( startNode ); if( removeIndex != -1 ) { //remove the appropriate genCountRemoved = this.RemoveGeneratedItems( removeIndex, removeIndex + countRemoved - 1, removedContainers ); } return retval; }
private bool FindGeneratorListMappingInformationForContainer( DependencyObject container, out GeneratorNode containerNode, out int containerRealizedIndex, out object containerDataItem ) { int index = m_genPosToContainer.IndexOf( container ); if( index == -1 ) { containerNode = null; containerRealizedIndex = -1; containerDataItem = null; return false; } containerNode = m_genPosToNode[ index ]; containerRealizedIndex = m_genPosToIndex[ index ]; containerDataItem = m_genPosToItem[ index ]; return true; }
public bool InsertBefore( GeneratorNode insert ) { if( insert == null ) throw new DataGridInternalException( "GeneratorNode is null" ); int insertionCount; int chainLength; GeneratorNode insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); GeneratorNode previous = m_currentNode.Previous; if( previous != null ) { previous.Next = insert; } insert.Previous = previous; m_currentNode.Previous = insertLast; insertLast.Next = m_currentNode; GroupGeneratorNode parentGroup = insert.Parent as GroupGeneratorNode; if( parentGroup != null ) { if( parentGroup.Child == m_currentNode ) { parentGroup.Child = insert; } } // Move the current to the first item inserted. // No need to change m_index, m_sourceDataIndex since they will still be with the correct value. m_currentNode = insert; return true; }
private GeneratorNode CreateGroupListFromCollection( IList collection, GeneratorNode parentNode ) { GeneratorNode rootNode = null; GeneratorNode previousNode = null; GroupGeneratorNode actualNode = null; GeneratorNode childNode = null; int level = ( parentNode == null ) ? 0 : parentNode.Level + 1; GroupConfiguration groupConfig; bool initiallyExpanded; ObservableCollection<GroupDescription> groupDescriptions = DataGridContext.GetGroupDescriptionsHelper( m_collectionView ); GroupConfigurationSelector groupConfigurationSelector = m_dataGridContext.GroupConfigurationSelector; foreach( CollectionViewGroup group in collection ) { groupConfig = GroupConfiguration.GetGroupConfiguration( m_dataGridContext, groupDescriptions, groupConfigurationSelector, level, group ); Debug.Assert( groupConfig != null, "groupConfig != null" ); #if LOG Log.Assert( this, groupConfig != null, "groupConfig != null" ); #endif if( groupConfig.UseDefaultHeadersFooters ) groupConfig.AddDefaultHeadersFooters(); initiallyExpanded = groupConfig.InitiallyExpanded; actualNode = ( GroupGeneratorNode )this.NodeFactory.CreateGroupGeneratorNode( group, parentNode, previousNode, null, groupConfig ); m_groupNodeMappingCache.Add( group, actualNode ); if( rootNode == null ) { rootNode = actualNode; } previousNode = actualNode; actualNode.UIGroup = new Group( actualNode, group, m_dataGridContext.GroupLevelDescriptions, m_dataGridContext ); //Independently if the Group is the bottom level or not, we need to setup GroupHeaders childNode = this.SetupGroupHeaders( groupConfig, actualNode ); actualNode.Child = childNode; GeneratorNodeHelper childNodeHelper = new GeneratorNodeHelper( childNode, 0, 0 ); //do not care about index. childNodeHelper.MoveToEnd(); //extensibility, just in case SetupGroupHeaders() ever return a node list. IList<object> subItems = group.GetItems(); //if the node newly created is not the bottom level if( !group.IsBottomLevel ) { if( ( subItems != null ) && ( subItems.Count > 0 ) ) { GeneratorNode subGroupsNode = this.CreateGroupListFromCollection( subItems as IList, actualNode ); if( subGroupsNode != null ) { childNodeHelper.InsertAfter( subGroupsNode ); } } } else { //this is the bottom level, create an Items node GeneratorNode itemsNode = this.NodeFactory.CreateItemsGeneratorNode( subItems as IList, actualNode, null, null, this ); if( itemsNode != null ) { childNodeHelper.InsertAfter( itemsNode ); } } childNodeHelper.InsertAfter( this.SetupGroupFooters( groupConfig, actualNode ) ); } return rootNode; }
//------------- // Methods internal virtual void CleanGeneratorNode() { this.Previous = null; this.Parent = null; this.Next = null; }
private GeneratorPosition HandleParentGroupRemove( GeneratorNode parent, out int countRemoved, out int genCountRemoved, out int removeIndex, NotifyCollectionChangedEventArgs e, IList<DependencyObject> removedContainers ) { GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). // start by moving to the first child... of the node (GroupHeaders node, most probably). // false parameter is to prevent skipping over a collapsed node (item count 0 ) if( !nodeHelper.MoveToChild( false ) ) { //could not advance to the child item so there is no items to be removed... throw new DataGridInternalException(); } return this.HandleSameLevelGroupRemove( nodeHelper.CurrentNode, out countRemoved, out genCountRemoved, out removeIndex, e, removedContainers ); }
internal GeneratorNode( GeneratorNode parent ) { this.Parent = parent; }
private GroupGeneratorNode ProcessGroupRemoval( GeneratorNode startNode, int removeCount, bool updateGroupNodeMappingCache, out int countRemoved ) { Debug.Assert( removeCount != 0, "remove count cannot be 0" ); #if LOG Log.Assert( this, removeCount != 0, "remove count cannot be 0" ); #endif GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( startNode, 0, 0 );//index not important. GroupGeneratorNode parentGroup = startNode.Parent as GroupGeneratorNode; int i = 0; countRemoved = 0; do { GroupGeneratorNode group = nodeHelper.CurrentNode as GroupGeneratorNode; if( updateGroupNodeMappingCache ) { m_groupNodeMappingCache.Remove( group.CollectionViewGroup ); } Debug.Assert( group != null, "node to be removed must be a GroupGeneratorNode" ); #if LOG Log.Assert( this, group != null, "node to be removed must be a GroupGeneratorNode" ); #endif //add the total number of child to the count of items removed. countRemoved += group.ItemCount; i++; if( i < removeCount ) { if( !nodeHelper.MoveToNext() ) { //could not advance to the last item to be removed... throw new DataGridInternalException(); } } } while( i < removeCount ); //disconnect the node chain to be removed from the linked list. GeneratorNode previous = startNode.Previous; GeneratorNode next = nodeHelper.CurrentNode.Next; if( next != null ) { next.Previous = previous; } if( previous != null ) { previous.Next = next; } //if the first node removed was the first child of its parent if( ( parentGroup != null ) && ( parentGroup.Child == startNode ) ) { //set the next in line after the chain to be removed as the first child parentGroup.Child = next; } //break the link between the chain and its same-level siblings. nodeHelper.CurrentNode.Next = null; startNode.Previous = null; //Here, I need a special handling case... If I remove the first group node, I need to set a new firstItem if( startNode == m_firstItem ) { if( next != m_firstFooter ) { m_firstItem = next; } else { m_firstItem = null; } if( m_startNode == startNode ) { m_startNode = next; } } Debug.Assert( nodeHelper.CurrentNode is GroupGeneratorNode, "last node is not a GroupGeneratorNode" ); #if LOG Log.Assert( this, nodeHelper.CurrentNode is GroupGeneratorNode, "last node is not a GroupGeneratorNode" ); #endif return ( GroupGeneratorNode )nodeHelper.CurrentNode; }
public HeadersFootersGeneratorNode(IList list, GeneratorNode parent) : base(list, parent) { }
private GeneratorNode HandleSameLevelGroupAddition( GeneratorNode firstChild, out int countAdded, NotifyCollectionChangedEventArgs e ) { Debug.Assert( ( ( firstChild.Parent == null ) || ( firstChild.Parent is GroupGeneratorNode ) ), "parent of the node should be a GroupGeneratorNode" ); #if LOG Log.Assert( this, ( ( firstChild.Parent == null ) || ( firstChild.Parent is GroupGeneratorNode ) ), "parent of the node should be a GroupGeneratorNode" ); #endif GeneratorNode newNodeChain = this.CreateGroupListFromCollection( e.NewItems, firstChild.Parent ); countAdded = 0; if( newNodeChain != null ) { int chainLength; GeneratorNodeHelper.EvaluateChain( newNodeChain, out countAdded, out chainLength ); GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); //do not care about index. //Advance to the first "Group" node (skip the GroupHEaders) while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) { if( !nodeHelper.MoveToNext() ) { //if there are no items and no groups in the Group Node, then we will never find a GroupGeneratorNode... //However, the structure of the group/headers/footers/group headers/groups footers makes it so //that inserting before the last item (footer/group footer) will place the group at the appropriate location. break; } } bool insertAfter = false; //If there is 0 group in the parent group, then this loop will exit without executing the control block once... for( int i = 0; i < e.NewStartingIndex; i++ ) { if( !nodeHelper.MoveToNext() ) { insertAfter = true; } } //if we are inserting past the end of the linked list level. if( insertAfter ) { nodeHelper.InsertAfter( newNodeChain ); } else { //we are inserting in the middle of the list nodeHelper.InsertBefore( newNodeChain ); } //If the insertion point is the beginning, check that the node pointers are updated properly if( ( e.NewStartingIndex == 0 ) && ( ( firstChild.Parent == null ) ) ) { if( m_startNode == m_firstItem ) { m_startNode = newNodeChain; } m_firstItem = newNodeChain; } } return newNodeChain; }
private void HandleItemAddition( GeneratorNode node, NotifyCollectionChangedEventArgs e ) { GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //index not important for now. node.AdjustItemCount( e.NewItems.Count ); ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; if( itemsNode != null ) { itemsNode.AdjustLeafCount( e.NewItems.Count ); this.OffsetDetails( itemsNode, e.NewStartingIndex, e.NewItems.Count ); } //if the node is totally expanded if( node.IsComputedExpanded ) { nodeHelper.ReverseCalculateIndex(); //invalidate the indexes this.IncrementCurrentGenerationCount(); int startIndex = nodeHelper.Index + e.NewStartingIndex; GeneratorPosition addGenPos = this.GeneratorPositionFromIndex( startIndex ); //and send notification message this.SendAddEvent( addGenPos, startIndex, e.NewItems.Count ); } }
internal GeneratorNode(GeneratorNode parent) { this.Parent = parent; }
private GeneratorPosition FindFirstRealizedItemsForNode( GeneratorNode referenceNode ) { GeneratorPosition retval = new GeneratorPosition( -1, 1 ); int genPosCounter = -1; List<GeneratorNode> nodesAccepted = new List<GeneratorNode>(); nodesAccepted.Add( referenceNode ); //if there are details for the reference node ItemsGeneratorNode itemsNode = referenceNode as ItemsGeneratorNode; if( ( itemsNode != null ) && ( itemsNode.Details != null ) ) { foreach( List<DetailGeneratorNode> details in itemsNode.Details.Values ) { foreach( DetailGeneratorNode detailNode in details ) { nodesAccepted.Add( detailNode ); } } } for( int i = 0; i < m_genPosToNode.Count; i++ ) { GeneratorNode node = m_genPosToNode[ i ]; //For master/detail, I have to decouple the index to genPos relationship (because of detail rows, possibly messing up with generated items. genPosCounter++; //if the node currently observed is my reference node, get it's computed generator position if( nodesAccepted.Contains( node ) ) { retval = new GeneratorPosition( genPosCounter, 0 ); break; } } return retval; }
internal NotifyCollectionChangedGeneratorNode(GeneratorNode parent) : base(parent) { }
private void SetStatContext( DependencyObject container, GeneratorNode node ) { GroupGeneratorNode parentGroup = node.Parent as GroupGeneratorNode; DataGridCollectionViewGroup cvg = null; if( parentGroup == null ) { DataGridCollectionViewBase dataGridCollectionViewBase = null; if( m_dataGridContext != null ) { dataGridCollectionViewBase = m_dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; } Debug.Assert( dataGridCollectionViewBase != null, "dataGridCollectionViewBase != null" ); if( dataGridCollectionViewBase != null ) cvg = dataGridCollectionViewBase.RootGroup as DataGridCollectionViewGroup; } else { cvg = parentGroup.CollectionViewGroup as DataGridCollectionViewGroup; } if( cvg != null ) container.SetValue( DataGridControl.StatContextPropertyKey, cvg ); }
internal ItemsGeneratorNode(IList list, GeneratorNode parent) : base(list, parent) { }