/// <summary> /// Balances the items. /// </summary> private void Balance() { if (!IsReady) { return; } double actualItemWidth = ActualItemWidth; double actualItemHeight = ActualItemHeight; _additionalItemsCount = (int)Math.Round((ActualHeight * 1.5) / actualItemHeight); LoopingSelectorItem closestToMiddle = null; int closestToMiddleIndex = -1; if (_itemsPanel.Children.Count == 0) { // We need to get the selection and start from there closestToMiddleIndex = 0; _selectedItem = closestToMiddle = CreateAndAddItem(_itemsPanel, DataSource.SelectedItem); closestToMiddle.Transform.Y = -actualItemHeight / 2; closestToMiddle.Transform.X = (ActualWidth - actualItemWidth) / 2; closestToMiddle.SetState(LoopingSelectorItem.State.Selected, false); } else { closestToMiddleIndex = GetClosestItem(); closestToMiddle = (LoopingSelectorItem)_itemsPanel.Children[closestToMiddleIndex]; } if (IsExpanded) { int itemsBeforeCount; LoopingSelectorItem firstItem = GetFirstItem(closestToMiddle, out itemsBeforeCount); int itemsAfterCount; LoopingSelectorItem lastItem = GetLastItem(closestToMiddle, out itemsAfterCount); // Does the top need items? if (itemsBeforeCount < itemsAfterCount || itemsBeforeCount < _additionalItemsCount) { while (itemsBeforeCount < _additionalItemsCount) { object newData = DataSource.GetPrevious(firstItem.DataContext); if (newData == null) { // There may be room to display more items, but there is no more data. _maximumPanelScroll = -firstItem.Transform.Y - actualItemHeight / 2; if (_isAnimating && _panelAnimation.To.Value > _maximumPanelScroll) { Brake(_maximumPanelScroll); } break; } LoopingSelectorItem newItem = null; // Can an item from the bottom be re-used? if (itemsAfterCount > _additionalItemsCount) { newItem = lastItem; lastItem = lastItem.Previous; newItem.Remove(); newItem.Content = newItem.DataContext = newData; } else { // Make a new item newItem = CreateAndAddItem(_itemsPanel, newData); newItem.Transform.X = (ActualWidth - actualItemWidth) / 2; } // Put the new item on the top newItem.Transform.Y = firstItem.Transform.Y - actualItemHeight; newItem.InsertBefore(firstItem); firstItem = newItem; ++itemsBeforeCount; } } // Does the bottom need items? if (itemsAfterCount < itemsBeforeCount || itemsAfterCount < _additionalItemsCount) { while (itemsAfterCount < _additionalItemsCount) { object newData = DataSource.GetNext(lastItem.DataContext); if (newData == null) { // There may be room to display more items, but there is no more data. _minimumPanelScroll = -lastItem.Transform.Y - actualItemHeight / 2; if (_isAnimating && _panelAnimation.To.Value < _minimumPanelScroll) { Brake(_minimumPanelScroll); } break; } LoopingSelectorItem newItem = null; // Can an item from the top be re-used? if (itemsBeforeCount > _additionalItemsCount) { newItem = firstItem; firstItem = firstItem.Next; newItem.Remove(); newItem.Content = newItem.DataContext = newData; } else { // Make a new item newItem = CreateAndAddItem(_itemsPanel, newData); newItem.Transform.X = (ActualWidth - actualItemWidth) / 2; } // Put the new item on the bottom newItem.Transform.Y = lastItem.Transform.Y + actualItemHeight; newItem.InsertAfter(lastItem); lastItem = newItem; ++itemsAfterCount; } } _temporaryItemsPool = null; } }