private LoopingSelectorItem CreateAndAddItem(Panel parent, object content) { bool reuse = _temporaryItemsPool != null && _temporaryItemsPool.Count > 0; LoopingSelectorItem wrapper = reuse ? _temporaryItemsPool.Dequeue() : new LoopingSelectorItem(); if (!reuse) { wrapper.ContentTemplate = this.ItemTemplate; wrapper.Width = ItemSize.Width; wrapper.Height = ItemSize.Height; wrapper.Padding = ItemMargin; wrapper.Click += OnWrapperClick; } wrapper.DataContext = wrapper.Content = content; parent.Children.Add(wrapper); // Need to do this before calling ApplyTemplate if (!reuse) { wrapper.ApplyTemplate(); wrapper.SetState(LoopingSelectorItem.State.Normal, false); } // Item should be visible if this control is expanded. if (IsExpanded) { // Uses transitions only when going from normal to expanded state. wrapper.SetState(LoopingSelectorItem.State.Expanded, !_actualIsExpanded); } return(wrapper); }
void OnWrapperClick(object sender, EventArgs e) { if (_state == State.Normal) { _state = State.Expanded; IsExpanded = true; } else if (_state == State.Expanded) { if (!_isAnimating && sender == _selectedItem) { _state = State.Normal; IsExpanded = false; } else if (sender != _selectedItem && !_isAnimating) { SelectAndSnapTo((LoopingSelectorItem)sender); _selectedItem.SetState(LoopingSelectorItem.State.Selected, true); } } }
/// <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; } }