示例#1
0
 internal static void RaiseAutomationEvent(this LoopingListItem loopingListItem)
 {
     if (loopingListItem.IsSelected)
     {
         loopingListItem.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementAddedToSelection);
     }
 }
        /// <summary>
        /// Scrolls to the desired index, starting from the provided visual item.
        /// </summary>
        /// <param name="item">The visual item to start from.</param>
        /// <param name="to">The target index to scroll to.</param>
        private void ScrollToIndex(LoopingListItem item, int to)
        {
            if (!this.IsInitialized())
            {
                return;
            }

            int from = item.LogicalIndex;

            if (item.LogicalIndex == to)
            {
                this.BringIntoView(to);
                return;
            }

            int indexOffset = Math.Abs(from - to);
            int pivotIndex  = this.logicalCount / 2;
            int sign        = Math.Sign(from - to);

            if (indexOffset > pivotIndex)
            {
                indexOffset = this.logicalCount - indexOffset;
                sign       *= -1;
            }

            double offset = this.visualOffset + (sign * indexOffset * this.itemLength);

            this.scrollState = LoopingPanelScrollState.ScrollingToIndex;
            this.AnimateVerticalOffset(offset);
        }
示例#3
0
        private double GetSnapOffset(LoopingListItem middleItem)
        {
            double middleOffset = this.GetSnapOffsetWhenCentered();
            double itemOffset   = this.orientation == Orientation.Vertical ? middleItem.VerticalOffset : middleItem.HorizontalOffset;

            return(this.visualOffset - (itemOffset - middleOffset));
        }
示例#4
0
        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.owner == null)
            {
                return;
            }

            this.size = e.NewSize;
            this.UpdateLayoutParams();
            this.UpdateVisualItemCount();

            if (this.visualCount != this.Children.Count)
            {
                this.UpdateChildren(true);
            }

            if (this.isCentered && this.owner != null)
            {
                LoopingListItem itemToCenter = this.FindMiddleItem();
                if (itemToCenter != null)
                {
                    this.CenterItem(itemToCenter, true, false);
                }
            }
        }
示例#5
0
        private void SelectTappedItem(LoopingListItem item)
        {
            if (!this.isExpanded)
            {
                this.IsExpanded = true;
                return;
            }

            if (item.isHidden || item.IsEmpty)
            {
                return;
            }

            if (!item.IsSelected)
            {
                if (this.isExpanded)
                {
                    this.SelectItem(item, LoopingListSelectionChangeReason.VisualItemClick);
                }
            }
            else if (this.AutoExpandCollapse)
            {
                // Toggle expand/collapse if the tap is over the selected item
                this.IsExpanded = !this.isExpanded;
            }

            if (item.IsSelected && this.itemsPanel != null && this.itemsPanel.IsCentered)
            {
                this.itemsPanel.CenterItem(item, false, true);
            }
        }
示例#6
0
        internal void CenterItem(LoopingListItem item, bool select, bool animate)
        {
            if (select && this.owner != null)
            {
                if (!this.owner.SelectItem(item, LoopingListSelectionChangeReason.VisualItemSnappedToMiddle))
                {
                    this.ScrollToIndex(item, this.owner.SelectedIndex, this.owner.SelectedVisualIndex);
                    return;
                }
            }

            if (animate)
            {
                double offset = this.GetSnapOffset(item);
                if (offset != this.visualOffset)
                {
                    this.ScrollState = LoopingPanelScrollState.SnapScrolling;
                    this.AnimateVerticalOffset(offset);
                }
            }
            else
            {
                this.BringIntoView(item.LogicalIndex, item.VisualIndex);
            }
        }
        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoopingListItem item = d as LoopingListItem;

            item.isSelected = (bool)e.NewValue;
            item.UpdateVisualState(false);
        }
示例#8
0
        /// <summary>
        /// Allows to minimize the overhead of creating new instances whenever a logical index changes by formatting an existing data item instance.
        /// </summary>
        internal virtual void UpdateDataItem(LoopingListDataItem dataItem, LoopingListItem visualItem)
        {
            if (this.ItemsSource != null)
            {
                dataItem.Item = this.ItemsSource[visualItem.LogicalIndex];
            }

            this.UpdateItemTemplate(dataItem, visualItem);
        }
        private void CenterMiddleItem(bool select, bool animate)
        {
            LoopingListItem middleItem = this.FindMiddleItem();

            if (middleItem == null)
            {
                return;
            }

            this.CenterItem(middleItem, select, animate);
        }
示例#10
0
 /// <summary>
 /// Brings the currently selected index into view and selects the visual item that represents it.
 /// </summary>
 internal virtual void SelectCurrentItem()
 {
     if (this.itemsPanel != null)
     {
         this.itemsPanel.BringIntoView(this.selectedIndex);
         LoopingListItem item = this.itemsPanel.ItemFromLogicalIndex(this.selectedIndex);
         if (item != null)
         {
             this.SelectItem(item, LoopingListSelectionChangeReason.User);
         }
     }
 }
示例#11
0
        private void SetDataItem(LoopingListItem visualItem)
        {
            LoopingListDataItem dataItem = visualItem.Content as LoopingListDataItem;

            if (dataItem == null)
            {
                dataItem = this.CreateDataItem(visualItem.LogicalIndex);
                visualItem.DataContext = dataItem;
                visualItem.Content     = dataItem;
            }

            this.UpdateDataItem(dataItem, visualItem);
        }
示例#12
0
        /// <summary>
        /// Associates the data at the specified logical index with the provided visual item instance.
        /// </summary>
        /// <param name="item">The visual item which data is to be updated.</param>
        /// <param name="logicalIndex">The logical index that describes the data.</param>
        /// <param name="visualIndex">The visual index that describes the data.</param>
        /// <param name="force">True to re-evaluate the data event if the visual item is already associated with the specified logical index.</param>
        /// <param name="animate">True to update the visual state using transitions.</param>
        internal void UpdateVisualItem(LoopingListItem item, int logicalIndex, int visualIndex, bool force, bool animate)
        {
            if ((!force && item.LogicalIndex == logicalIndex && item.VisualIndex == visualIndex) || item.IsEmpty)
            {
                return;
            }

            item.LogicalIndex = logicalIndex;
            item.VisualIndex  = visualIndex;

            this.UpdateItemVisualState(item, new VisualStateUpdateParams(animate, true, true));
            this.SetDataItem(item);
        }
示例#13
0
        private LoopingListItem CreateVisualItem()
        {
            if (this.owner == null)
            {
                return(null);
            }

            LoopingListItem item = this.owner.CreateVisualItem();

            item.Attach(this);
            this.items.Add(item);

            return(item);
        }
示例#14
0
        /// <summary>
        /// Provides the behavior for the Arrange pass of Silverlight layout. Classes can override this method to define their own Arrange pass behavior.
        /// </summary>
        /// <param name="finalSize">The final area within the parent that this object should use to arrange itself and its children.</param>
        /// <returns>
        /// The actual size that is used after the element is arranged in layout.
        /// </returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            double position = 0;

            this.owner.UpdateSelectedVisualIndex();

            for (int i = 0; i < this.visualCount; i++)
            {
                LoopingListItem item = this.items[i];

                Size desired = item.DesiredSize;
                if (!item.IsEmpty)
                {
                    Rect rect;

                    if (this.orientation == Orientation.Vertical)
                    {
                        rect = new Rect(0, position, desired.Width, desired.Height);
                    }
                    else
                    {
                        rect = new Rect(position, 0, desired.Width, desired.Height);
                    }

                    item.Arrange(rect);
                    item.ArrangeRect = rect;
                }

                position += this.orientation == Orientation.Vertical ? desired.Height : desired.Width;
            }

            if (this.isCentered && !this.centeringDuringLayout)
            {
                this.centeringDuringLayout = true;
                if (this.owner != null && this.owner.SelectedVisualIndex != -1)
                {
                    this.BringIntoView(this.owner.SelectedIndex, this.owner.SelectedVisualIndex);
                }
                else
                {
                    this.CenterMiddleItem(false, false);
                }
            }
            else
            {
                this.centeringDuringLayout = false;
            }

            return(finalSize);
        }
示例#15
0
        private void OnIsLoopingEnabledChanged()
        {
            if (this.owner == null)
            {
                return;
            }

            this.StopOffsetAnimation(false);

            if (this.items.Count == 0)
            {
                return;
            }

            if (!this.isLoopingEnabled)
            {
                this.UpdateWheel(0, false);

                for (int i = 0; i < this.items.Count; i++)
                {
                    LoopingListItem item = this.items[i];

                    if (i >= this.logicalCount)
                    {
                        item.SetIsEmpty(true);
                    }
                }

                var offset = -this.owner.SelectedIndex * this.itemLength;
                if (this.isCentered)
                {
                    offset += this.GetSnapOffsetWhenCentered();
                }

                this.UpdateWheel(offset, false);
            }
            else
            {
                foreach (LoopingListItem item in this.items)
                {
                    item.SetIsEmpty(false);
                }

                this.InvalidateMeasure();
                this.UpdateWheel(this.visualOffset, true);
            }

            this.owner.UpdateSelection(this.owner.SelectedIndex, this.owner.GetVisualIndex(this.owner.SelectedIndex), LoopingListSelectionChangeReason.Private);
        }
示例#16
0
 /// <summary>
 /// Centers the item at the currently selected index.
 /// </summary>
 internal void CenterCurrentItem(bool animate)
 {
     if (this.itemsPanel != null)
     {
         LoopingListItem item = this.itemsPanel.ItemFromVisualIndex(this.selectedVisualIndex);
         if (item != null)
         {
             this.itemsPanel.CenterItem(item, false, animate);
         }
         else
         {
             this.itemsPanel.BringIntoView(this.selectedIndex, this.selectedVisualIndex);
         }
     }
 }
示例#17
0
        private void UpdateItemTemplate(LoopingListDataItem dataItem, LoopingListItem visualItem)
        {
            DataTemplate         template = null;
            DataTemplateSelector selector = this.itemTemplateSelectorCache;

            if (selector != null)
            {
                template = selector.SelectTemplate(dataItem, visualItem);
            }

            if (template == null)
            {
                template = this.itemTemplateCache;
            }

            visualItem.ContentTemplate = template;
        }
示例#18
0
        /// <summary>
        /// Creates a <see cref="LoopingListItem"/> instance to be used by the hosted <see cref="LoopingPanel"/>.
        /// </summary>
        internal LoopingListItem CreateVisualItem()
        {
            LoopingListItem item = this.CreateVisualItemInstance();

            item.Width  = this.ItemWidth;
            item.Height = this.ItemHeight;

            double spacing = this.ItemSpacing;

            item.Margin = this.orientationCache == Orientation.Vertical ? new Thickness(0, spacing, 0, spacing) : new Thickness(spacing, 0, spacing, 0);

            if (this.itemStyleCache != null)
            {
                item.Style = this.itemStyleCache;
            }

            return(item);
        }
示例#19
0
        private void CenterMiddleItem(bool select, bool animate)
        {
            LoopingListItem middleItem = this.FindMiddleItem();

            if (middleItem == null)
            {
                if (this.items.Count > 0)
                {
                    middleItem = this.items[0];
                }
                else
                {
                    return;
                }
            }

            this.CenterItem(middleItem, select, animate);
        }
        private void OnIsLoopingEnabledChanged()
        {
            if (this.owner == null)
            {
                return;
            }

            this.StopOffsetAnimation(false);

            if (this.items.Count == 0)
            {
                return;
            }

            if (!this.isLoopingEnabled)
            {
                double normalizedOffset = this.visualOffset % (this.logicalCount * this.itemLength);
                normalizedOffset = normalizedOffset > 0 ? normalizedOffset - (this.itemLength * this.logicalCount) : normalizedOffset;
                normalizedOffset = this.ClampOffset(normalizedOffset);
                this.UpdateWheel(0, false);

                for (int i = 0; i < this.items.Count; i++)
                {
                    LoopingListItem item = this.items[i];

                    if (i > this.logicalCount - 1)
                    {
                        item.SetIsEmpty(true);
                    }
                }

                this.UpdateWheel(normalizedOffset, false);
            }
            else
            {
                foreach (LoopingListItem item in this.items)
                {
                    item.SetIsEmpty(false);
                }
            }

            this.UpdateWheel(this.visualOffset, true);
        }
示例#21
0
        /// <summary>
        /// Selects the specified visual item.
        /// </summary>
        /// <param name="item">The item to be selected.</param>
        /// <param name="reason">The reason that caused the select request.</param>
        internal virtual bool SelectItem(LoopingListItem item, LoopingListSelectionChangeReason reason)
        {
            if (!this.CanChangeSelectedIndex(item.LogicalIndex))
            {
                return(false);
            }

            if (!item.IsSelected)
            {
                // update the selected index
                this.UpdateSelection(item.LogicalIndex, item.VisualIndex, reason);
            }
            else
            {
                this.UpdateItemsIsSelectedState();
            }

            return(true);
        }
示例#22
0
        internal LoopingListItem GetFirstVisibleItem()
        {
            LoopingListItem topItem = null;
            double          offset  = double.MaxValue;

            foreach (LoopingListItem item in this.Children)
            {
                if (!item.IsEmpty && !item.isHidden)
                {
                    var itemOffset = this.orientation == Orientation.Horizontal ? item.HorizontalOffset : item.VerticalOffset;

                    if (itemOffset < offset)
                    {
                        offset  = itemOffset;
                        topItem = item;
                    }
                }
            }

            return(topItem);
        }
示例#23
0
        private void TranslateItems(int startIndex, int endIndex, double offset)
        {
            for (int i = startIndex; i < endIndex; i++)
            {
                LoopingListItem item = this.items[i];
                if (!item.IsEmpty)
                {
                    if (this.orientation == Orientation.Vertical)
                    {
                        item.SetVerticalOffset(offset);
                    }
                    else
                    {
                        item.SetHorizontalOffset(offset);
                    }

                    if (!this.isLoopingEnabled)
                    {
                        double itemOffset = this.orientation == Orientation.Vertical ? item.VerticalOffset : item.HorizontalOffset;
                        itemOffset = Math.Round(itemOffset, 2);
                        double thisOffset = Math.Round(this.visualOffset, 2);
                        double maxOffset  = Math.Round((this.logicalCount * this.itemLength) + this.visualOffset, 2);

                        if (maxOffset <= itemOffset || itemOffset - thisOffset < 0)
                        {
                            item.SetIsHidden(true);
                        }
                        else
                        {
                            item.SetIsHidden(false);
                        }
                    }
                    else
                    {
                        item.SetIsHidden(false);
                    }
                }
                this.visualIndexChain.Add(i);
            }
        }
示例#24
0
        private void CreateVisualItems()
        {
            int oldCount = this.visualCount;

            this.UpdateVisualItemCount();
            if (this.visualCount == 0 || this.visualCount == oldCount && this.items.Count >= this.visualCount)
            {
                return;
            }

            if (this.visualCount != oldCount || this.items.Count < this.visualCount)
            {
                this.Children.Clear();
                this.visualIndexChain.Clear();
                this.items.Clear();
            }

            for (int i = 0; i < this.visualCount; i++)
            {
                LoopingListItem item = this.CreateVisualItem();
                this.Children.Add(item);
                this.visualIndexChain.Add(i);

                if (!this.isLoopingEnabled && i > this.logicalCount - 1)
                {
                    item.SetIsEmpty(true);
                }
            }

            if (this.topLogicalIndex == 0 || this.visualCount != oldCount)
            {
                this.UpdateIndexes(this.visualCount != oldCount, false);
            }
            else
            {
                this.BringIntoView(this.topLogicalIndex, this.visualIndexChain[0]);
            }
        }
示例#25
0
        /// <summary>
        /// Updates the visual state of a single item.
        /// </summary>
        /// <param name="item">The <see cref="LoopingListItem"/> instance which state is to be updated.</param>
        /// <param name="updateParams">The structure that encapsulates different update parameters such as Animate, EvaluateEnabled, etc.</param>
        internal virtual void UpdateItemVisualState(LoopingListItem item, VisualStateUpdateParams updateParams)
        {
            if (item.IsEmpty)
            {
                return;
            }

            int logicalIndex = item.LogicalIndex;

            item.BeginVisualStateUpdate();

            if (updateParams.EvaluateEnabled)
            {
                item.IsEnabled = this.IsItemEnabled(logicalIndex);
            }

            if (updateParams.EvaluateSelected)
            {
                item.IsSelected = this.IsItemSelected(logicalIndex);
            }

            item.EndVisualStateUpdate(true, updateParams.Animate);
        }
示例#26
0
        /// <summary>
        /// Called before the Tapped event occurs.
        /// </summary>
        protected override void OnTapped(TappedRoutedEventArgs e)
        {
            base.OnTapped(e);

            if (e == null)
            {
                return;
            }

            if (this.skipTapped)
            {
                this.skipTapped = false;
                return;
            }

            Point           hitPoint   = e.GetPosition(this);
            LoopingListItem tappedItem = this.itemsPanel.ItemFromOffset(this.Orientation == Orientation.Vertical ? hitPoint.Y : hitPoint.X);

            if (tappedItem != null)
            {
                this.OnVisualItemTap(tappedItem);
            }
        }
示例#27
0
        internal void UpdateIndexes(bool force, bool animate)
        {
            this.topLogicalIndex = this.GetFirstRealizedIndex(this.logicalCount);

            int itemCount           = this.visualIndexChain.Count;
            int currentLogicalIndex = this.topLogicalIndex;

            for (int i = 0; i < itemCount; i++)
            {
                LoopingListItem item = this.items[this.visualIndexChain[i]];

                if (currentLogicalIndex == this.logicalCount)
                {
                    currentLogicalIndex = 0;
                }

                if (this.owner != null && !item.IsEmpty)
                {
                    this.owner.UpdateVisualItem(item, currentLogicalIndex, this.visualIndexChain[i], force, animate);
                }

                currentLogicalIndex++;
            }
        }
示例#28
0
 /// <summary>
 /// Handles a Double-tap event from a child <see cref="LoopingListItem"/>.
 /// </summary>
 internal virtual void OnVisualItemDoubleTap(LoopingListItem item)
 {
     this.SelectTappedItem(item);
 }
示例#29
0
 /// <summary>
 /// Allows to minimize the overhead of creating new instances whenever a logical index changes by formatting an existing data item instance.
 /// </summary>
 /// <param name="dataItem"></param>
 /// <param name="visualItem"></param>
 internal virtual void UpdateDataItem(LoopingListDataItem dataItem, LoopingListItem visualItem)
 {
     this.UpdateItemTemplate(dataItem, visualItem);
 }