/// <summary>
        /// Get the range of children that are visible
        /// </summary>
        /// <param name="firstVisibleItemIndex">The item index of the first visible item</param>
        /// <param name="lastVisibleItemIndex">The item index of the last visible item</param>
        private VisibleRange GetVisibleRange()
        {
            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
            int itemCount = itemsControl.HasItems ? itemsControl.Items.Count : 0;

            if (itemCount == 0)
            {
                return VisibleRange.Empty;
            }
            else {
                int columns = DataSource.Source.Columns.Length;

                VisibleRange range = new VisibleRange();
                range.firstRow = Math.Max(0,(int)Math.Floor(_offset.Y / PropertiesGridControl.RowHeight) - CREATE_MARGIN_ELEMENTS);
                range.firstCol = (int)Math.Floor(_offset.X / PropertiesGridControl.DataItemWidth);
                range.rowCount = (int)Math.Ceiling((_viewport.Height) / PropertiesGridControl.RowHeight) + (CREATE_MARGIN_ELEMENTS*2) + 1; //Anstatt +1 wäre korrekterweise der ausgeblendete Teil der ersten Zeile zu beachten
                range.colCount = Math.Min(columns-range.firstCol,(int)Math.Ceiling((_viewport.Width) / PropertiesGridControl.DataItemWidth) + 1); //--||--

                int lastIndex = (range.firstRow + range.rowCount) * columns + range.firstCol + range.colCount;
                if (lastIndex >= itemCount)
                {
                    //Anzeige kann nicht komplett ausgefüllt werden
                    int maxRowCount = Math.Max(0, itemCount / columns - range.firstRow);
                    range.rowCount =  Math.Min(maxRowCount, range.rowCount);
                }
                return range;
            }
        }
        /// <summary>
        /// Revirtualize items that are no longer visible
        /// </summary>
        private void CleanUpItems(VisibleRange visibleRange, int columCount)
        {
            UIElementCollection children = this.InternalChildren;
            if (children.Count > 0)
            {
                ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
                IItemContainerGenerator generator = this.ItemContainerGenerator;

                int firstVisibleIndex = visibleRange.firstRow * columCount + visibleRange.firstCol;
                int lastVisibleIndex = (visibleRange.firstRow + visibleRange.rowCount) * columCount + visibleRange.firstCol + visibleRange.colCount;

                for (int i = children.Count - 1; i >= 0; i--)
                {
                    GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0);
                    int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos);

                    if (itemIndex < firstVisibleIndex || itemIndex > lastVisibleIndex)
                    {
                        if (!((ItemViewModel)itemsControl.Items.GetItemAt(itemIndex)).InEditMode)
                        {
                            generator.Remove(childGeneratorPos, 1);
                            RemoveInternalChildRange(i, 1);
                        }
                    }
                }
            }
        }
        protected override Size MeasureOverride(Size availableSize)
        {
            UpdateScrollInfo(availableSize);

            // Figure out range that's visible based on layout algorithm
            VisibleRange visibleRange = GetVisibleRange();
            _prevVisibleRange = visibleRange;
            if (SCROLL_CREATE_ITEMS_DELAY_MS == 0)
            {
                CalculateChildren(visibleRange);
            }
            else
            {
                Task.Delay(SCROLL_CREATE_ITEMS_DELAY_MS).ContinueWith((t) =>
                {
                //Wartet für die angegeben Zeitspanne
                //Falls sich der angezeigte Bereich in dieser Zeit nicht geändert hat
                // -> Child-Element erzeugen
                if (visibleRange.Equals(_prevVisibleRange) && !visibleRange.Equals(_calculatedVisibleRange))
                    {
                        _calculatedVisibleRange = visibleRange;
                        CalculateChildren(visibleRange);
                    }
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }

            return availableSize;
        }
        private void CalculateChildren(VisibleRange visibleRange)
        {
            // We need to access InternalChildren before the generator to work around a bug
            UIElementCollection children = this.InternalChildren;
            IItemContainerGenerator generator = this.ItemContainerGenerator;

            int columCount = DataSource.Source.Columns.Length;
            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);

            int lastRow = visibleRange.firstRow + visibleRange.rowCount;
            for (int r = visibleRange.firstRow; r < lastRow; r++)
            {
                int firstVisibleItemInRow = r * columCount + visibleRange.firstCol;
                int lastVisibleItemInRow = firstVisibleItemInRow + visibleRange.colCount - 1;
                GeneratorPosition startPos = generator.GeneratorPositionFromIndex(firstVisibleItemInRow);

                // Get index where we'd insert the child for this position. If the item is realized
                // (position.Offset == 0), it's just position.Index, otherwise we have to add one to
                // insert after the corresponding child
                int childIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1;

                using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
                {
                    for (int itemIndex = firstVisibleItemInRow; itemIndex <= lastVisibleItemInRow; ++itemIndex, ++childIndex)
                    {
                        if (((ItemViewModel)itemsControl.Items[itemIndex]).Item != null)
                        {
                            bool newlyRealized;

                            // Get or create the child
                            UIElement child = generator.GenerateNext(out newlyRealized) as UIElement;
                            if (newlyRealized)
                            {
                                // Figure out if we need to insert the child at the end or somewhere in the middle
                                if (childIndex >= children.Count)
                                {
                                    base.AddInternalChild(child);
                                }
                                else
                                {
                                    base.InsertInternalChild(childIndex, child);
                                }
                                generator.PrepareItemContainer(child);
                                this.DataSource.HoverManager.RegisterItem(child);
                            }
                            else
                            {
                                // The child has already been created, let's be sure it's in the right spot
                                //Debug.Assert(child == children[childIndex], "Wrong child was generated");
                            }

                            // Measurements will depend on layout algorithm
                            if (child != null)
                                child.Measure(GetChildSize());
                        }
                    }
                }
            }

            // Note: this could be deferred to idle time for efficiency
            CleanUpItems(visibleRange, columCount);
        }
 public void Refresh()
 {
     _calculatedVisibleRange = VisibleRange.Empty;
 }