private void OnCustomGeneratorItemsChanged(object sender, CustomGeneratorChangedEventArgs e)
        {
            switch (e.Action)
            {
            //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already!
            case NotifyCollectionChangedAction.Reset:
                if (this.InternalChildren.Count > 0)
                {
                    this.RemoveInternalChildRange(0, this.InternalChildren.Count);
                }
                else
                {
                    this.InvalidateMeasure();
                }

                break;

            //If there was a removal (collapsing)
            //or if there was a Move (edition of a Sorted field)
            case NotifyCollectionChangedAction.Move:
            case NotifyCollectionChangedAction.Remove:
                //remove the concerned range
                int index = e.OldPosition.Index;
                if (e.OldPosition.Offset != 0)
                {
                    index++;
                }

                this.RemoveInternalChildRange(index, e.ItemUICount);
                break;

            //if some items were added (expansion)
            case NotifyCollectionChangedAction.Add:
                //invalidate layout so that the items will be inserted in place!
                this.InvalidateMeasure();
                break;

            case NotifyCollectionChangedAction.Replace:
                Debug.Fail("NotifyCollectionChangedAction.Replace");
                break;

            default:
                break;
            }
        }
        private void HandleGeneratorItemsChanged(object sender, CustomGeneratorChangedEventArgs e)
        {
            switch (e.Action)
            {
            case NotifyCollectionChangedAction.Add:
            {
                this.OnItemsAdded(e.Position, e.Index, e.ItemCount);
                break;
            }

            case NotifyCollectionChangedAction.Move:
            {
                this.OnItemsMoved(e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers);
                break;
            }

            case NotifyCollectionChangedAction.Remove:
            {
                this.OnItemsRemoved(e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers);
                break;
            }

            case NotifyCollectionChangedAction.Replace:
            {
                this.OnItemsReplaced(e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers);
                break;
            }

            case NotifyCollectionChangedAction.Reset:
            {
                this.OnItemsReset();
                break;
            }

            default:
            {
                throw new System.ComponentModel.InvalidEnumArgumentException("An unknown action was specified.");
            }
            }
        }
        private void HandleGeneratorItemsChanged(object sender, CustomGeneratorChangedEventArgs e)
        {
            // We set this flag to delay any bring into view until a layout pass occured if there is one.
            // We don't want the bring into view to occur on a container that may move around during the layout pass.
            this.DelayBringIntoView = true;

            switch (e.Action)
            {
            case NotifyCollectionChangedAction.Add:
                this.OnItemsAdded();
                break;

            case NotifyCollectionChangedAction.Remove:
                this.OnItemsRemoved(e.Containers);
                break;

            default:
                this.OnItemsReset();
                break;
            }

            this.Dispatcher.BeginInvoke(new Action(() => this.DelayBringIntoView = false), DispatcherPriority.Loaded);
        }
    private void HandleDetailMoveRemove( object masterItem, DetailGeneratorNode detailNode, CustomGeneratorChangedEventArgs e )
    {
      GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
      int masterIndex = nodeHelper.FindItem( masterItem );

      //If the masterItem is part of an ItemsGeneratorNode which is below a collapsed group, masterIndex will be -1
      if( masterIndex == -1 )
      {
        //in that case, I need to determine the appropriate masterNode another way
        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

      int globalIndex = -1;
      GeneratorPosition convertedGeneratorPosition = ( masterIndex != -1 ) ? this.ConvertDetailGeneratorPosition( e.OldPosition, masterItem, detailNode, out globalIndex ) : new GeneratorPosition( -1, 1 );

      if( masterIndex != -1 )
      {
        this.RemoveDetailContainers( convertedGeneratorPosition, e.ItemUICount );
      }

      if( e.Action == NotifyCollectionChangedAction.Remove )
      {
        masterNode.AdjustItemCount( -e.ItemCount );

        detailNode.UpdateItemCount();
      }

      this.IncrementCurrentGenerationCount();

      if( masterIndex != -1 )
      {
        this.SendRemoveEvent( convertedGeneratorPosition, globalIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers );
      }
    }
    private void HandleDetailGeneratorContentChanged( object sender, CustomGeneratorChangedEventArgs e )
    {
      Debug.Assert( m_isProcessingGlobalResetOrRemovingAllGeneratedItemsDisposableCount == 0, "Generator is already processing a HandleGlobalItemReset or CleanupGenerator" );
#if LOG
      Log.Assert( this, m_isProcessingGlobalResetOrRemovingAllGeneratedItemsDisposableCount == 0, "Generator is already processing a HandleGlobalItemReset or CleanupGenerator" );
#endif

      if( m_isProcessingGlobalResetOrRemovingAllGeneratedItemsDisposableCount > 0 )
        return;

      using( new ProcessingGlobalItemsResetOrRemovingAllGeneratedItemsDisposable( this ) )
      {
        Debug.Assert( m_startNode != null, "m_startNode != null" );
#if LOG
        Log.Assert( this, m_startNode != null, "m_startNode != null" );
#endif

        CustomItemContainerGenerator detailGenerator = sender as CustomItemContainerGenerator;

        Debug.Assert( detailGenerator != null, "detailGenerator != null" );
#if LOG
        Log.Assert( this, detailGenerator != null, "detailGenerator != null" );
#endif

        object masterItem;
        DetailGeneratorNode detailNode = this.FindDetailGeneratorNodeForGenerator( detailGenerator, out masterItem );

        Debug.Assert( masterItem != null, "masterItem != null" );
        Debug.Assert( detailNode != null, "detailNode != null" );
#if LOG
        Log.Assert( this, masterItem != null, "masterItem != null" );
        Log.Assert( this, detailNode != null, "detailNode != null" );
#endif

        if( ( detailNode != null ) && ( masterItem != null ) )
        {
          switch( e.Action )
          {
            case NotifyCollectionChangedAction.Add:
              this.HandleDetailAddition( masterItem, detailNode, e );
              break;

            case NotifyCollectionChangedAction.Move:
            case NotifyCollectionChangedAction.Remove:
              this.HandleDetailMoveRemove( masterItem, detailNode, e );
              break;

            case NotifyCollectionChangedAction.Replace: //CustomItemContainerGenreator never issues a Replace!
              throw new DataGridInternalException();

            case NotifyCollectionChangedAction.Reset:
              this.HandleDetailReset( masterItem, detailNode );
              break;

            default:
              break;
          }
        }
      }
    }
    private void OnCustomGeneratorItemsChanged( object sender, CustomGeneratorChangedEventArgs e )
    {

      switch( e.Action )
      {
        //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already!
        case NotifyCollectionChangedAction.Reset:
          if ( this.InternalChildren.Count > 0 )
          {
            this.RemoveInternalChildRange( 0, this.InternalChildren.Count );
          }
          else
          {
            this.InvalidateMeasure();
          }

          break;

        //If there was a removal (collapsing)
        //or if there was a Move (edition of a Sorted field)
        case NotifyCollectionChangedAction.Move:
        case NotifyCollectionChangedAction.Remove:
          //remove the concerned range
          int index = e.OldPosition.Index;
          if(e.OldPosition.Offset != 0)
          {
            index++;
          }

          this.RemoveInternalChildRange( index, e.ItemUICount );
          break;

        //if some items were added (expansion)
        case NotifyCollectionChangedAction.Add:
          //invalidate layout so that the items will be inserted in place!
          this.InvalidateMeasure();
          break;

        case NotifyCollectionChangedAction.Replace:
          Debug.Fail("NotifyCollectionChangedAction.Replace");
          break;

        default:
          break;
      }
    }
 private void HandleGeneratorItemsChanged( object sender, CustomGeneratorChangedEventArgs e )
 {
   switch( e.Action )
   {
     case NotifyCollectionChangedAction.Add:
       {
         this.OnItemsAdded( e.Position, e.Index, e.ItemCount );
         break;
       }
     case NotifyCollectionChangedAction.Move:
       {
         this.OnItemsMoved( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers );
         break;
       }
     case NotifyCollectionChangedAction.Remove:
       {
         this.OnItemsRemoved( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers );
         break;
       }
     case NotifyCollectionChangedAction.Replace:
       {
         this.OnItemsReplaced( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers );
         break;
       }
     case NotifyCollectionChangedAction.Reset:
       {
         this.OnItemsReset();
         break;
       }
     default:
       {
         throw new System.ComponentModel.InvalidEnumArgumentException( "An unknown action was specified." );
       }
   }
 }
        private void OnCustomGeneratorItemsChanged(object sender, CustomGeneratorChangedEventArgs e)
        {
            switch (e.Action)
            {
            //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already!
            case NotifyCollectionChangedAction.Reset:
            {
                if (this.InternalChildren.Count > 0)
                {
                    this.RemoveInternalChildRange(0, this.InternalChildren.Count);
                }
                else
                {
                    this.InvalidateMeasure();
                }
            }
            break;

            //If there was a removal (collapsing)
            //or if there was a Move (edition of a Sorted field)
            case NotifyCollectionChangedAction.Move:
            case NotifyCollectionChangedAction.Remove:
            {
                var containers = new HashSet <DependencyObject>(e.Containers ?? new DependencyObject[0]);

                if (containers.Count > 0)
                {
                    var children    = this.InternalChildren;
                    var from        = -1;
                    var removeCount = 0;
                    var i           = 0;

                    while (i < children.Count)
                    {
                        var container = children[i];

                        if (containers.Contains(container))
                        {
                            containers.Remove(container);

                            if (from < 0)
                            {
                                from = i;
                            }

                            removeCount++;
                            i++;
                        }
                        else if (removeCount > 0)
                        {
                            Debug.Assert(from >= 0);
                            this.RemoveInternalChildRange(from, removeCount);

                            from        = -1;
                            removeCount = 0;
                        }
                        else
                        {
                            i++;
                        }
                    }

                    if (removeCount > 0)
                    {
                        Debug.Assert(from >= 0);
                        this.RemoveInternalChildRange(from, removeCount);
                    }
                }
                else
                {
                    this.InvalidateMeasure();
                }
            }
            break;

            //if some items were added (expansion)
            case NotifyCollectionChangedAction.Add:
            {
                //invalidate layout so that the items will be inserted in place!
                this.InvalidateMeasure();
            }
            break;

            case NotifyCollectionChangedAction.Replace:
            {
                Debug.Fail("NotifyCollectionChangedAction.Replace");
            }
            break;

            default:
                break;
            }
        }