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 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(); }
private GeneratorNode SetupInitialItemsNodes( out int addCount ) { //TODO ( case 117275 ): Check the amount of time this is executed for a single grid being populated! GeneratorNode newItemNode = null; addCount = 0; this.RefreshGroupsCollection(); //this function should only be called when the m_firstItem is null. if( m_groupsCollection != null ) { newItemNode = this.CreateGroupListFromCollection( m_groupsCollection, null ); } else { newItemNode = this.CreateStandaloneItemsNode(); } //if the node is non-null, then that's because there was items in the collection if( newItemNode != null ) { m_firstItem = newItemNode; int chainLength; GeneratorNodeHelper.EvaluateChain( m_firstItem, out addCount, out chainLength ); //find the appropriate point to inject the Items nodes... if( m_startNode != null ) { //if there is a footer node, then the insertion point is just before the footer node (if there is anything before!) if( m_firstFooter != null ) { GeneratorNode originalPrevious = m_firstFooter.Previous; GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_firstFooter, 0, 0 ); //do not care about index! nodeHelper.InsertBefore( m_firstItem ); if( originalPrevious == null ) //that means that the first footer is the first item { m_startNode = newItemNode; } } else if( m_firstHeader != null ) //if there is no footer but some headers, add it at the end. { GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_firstHeader, 0, 0 ); //do not care about index! nodeHelper.MoveToEnd(); nodeHelper.InsertAfter( m_firstItem ); } else { throw new DataGridInternalException(); //this case should not be possible: no header, no footers but there is a startNode } } else { m_startNode = m_firstItem; #if LOG Log.WriteLine( this, "SetupInitialItemsNodes - new tree" ); #endif } } return newItemNode; }
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; }
private void UpdateFooters( IList footers ) { //if there was no header prior this udpate. if( m_firstFooter == null ) { //create the node(s) that would contain the footers m_firstFooter = this.CreateFooters( footers ); //if there are no footers, then the m_firstFooter will remain null if( m_firstFooter != null ) { int count; int chainLength; GeneratorNodeHelper.EvaluateChain( m_firstFooter, out count, out chainLength ); //if there was items present in the linked list. if( m_startNode != null ) { //since we called ClearFooters earlier, I can just go at the end of the list of items GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); nodeHelper.MoveToEnd(); nodeHelper.InsertAfter( m_firstFooter ); } else { m_startNode = m_firstFooter; #if LOG Log.WriteLine( this, "UpdateFooters - new tree" ); #endif } } } //If the m_firstHeader is not NULL, then there is nothing to do, since the Header node contains an observable collection //which we monitor otherwise. }