0

我正在尝试实现无限的日历样式(基于日期)FlipView,用户可以通过触摸滚动。我正在将FlipView'sItemTemplate与 custom绑定ObservableCollection。一切都很好地显示出来,我正在操纵ObservableCollection以提供所需的行为:当更改选定的索引时,将新元素添加到顶部,然后从底部删除。

private void OnIndexChanged(object sender, SelectionChangedEventArgs e)
        {
            //Works great on slow swiping with pauses, no offset artifacts
            DataGroup.OnIndexChanged(GroupFlip.SelectedIndex);
        }

问题是,FlipView只会SelectedIndex在用户停止滚动时触发 changed 事件。对于小刷,这很好,但用户很容易到达集合的末尾并走到死胡同,直到集合更新。

我已经成功订阅了FlipViewinner ScrollViewer's [Viewchanged][1],如此处所建议的,并且能够查看并使用HorizontalOffset来计算新的索引偏移量并操作集合。

问题是,当在此事件中操作集合时,会FlipView以各种方式跳转,具体取决于用户和集合的操作类型。

InnerFlipper.ViewChanged += OnSoftScroll;//InnerFlipper is caught from the `VisualHelperTree`        
private void OnSoftScroll(object sender, ScrollViewerViewChangedEventArgs e)
    {
        (...)
        double UpperMargin = ScrollableSize - Offset;//Value is reliable
        if (UpperMargin < ViewObservableSize)
        {
            DataGroup.OnIndexDelta(1);
        }
        (...)
    }

我尝试了许多忽略某些事件以避免双重触发的组合,强制新HorizontalOffset的基于索引更改和当前偏移量的计算值等。没有给出透明的结果,这是一个无缝的无限滚动。

任何想法如何避免工件,处理此事件或什至以其他方式实施以实现预期结果?

4

1 回答 1

1

最后通过完全重建 FlipView 的工作方式解决了这个问题。如果 FlipView 是用一个非常大的“虚拟”集(即没有内容)初始化的,那么滚动时我所要做的就是更新内容,而不是弄乱 FlipView 的索引或项目计数。

希望它可以帮助其他人。

编辑:

我从实现中制作了一个代码片段。然而,回首过去,它只是乞求也使用可回收模式,以防止大量滚动时出现大量 GC。更新的大型虚拟列表的概念仍然存在。我正在使用通用对象,因为我的视图切换了每个页面的自定义控件类型(周页面、月页面等)。希望它可以帮助你们,快乐的编码。

在控件方面,我们有一个 FlipView,其中仅订阅了 Loaded 事件。

    protected ScrollViewer InnerScroller;

    private void OnFlipViewerLoaded(object sender, RoutedEventArgs e)
    {
        InnerFlipper = (ScrollViewer)FindChildControl<ScrollViewer>(sender);
        InnerFlipper.ViewChanged += OnPageScroll;
    }

    /// <summary>
    /// Our custom pseudo-infinite collection
    /// </summary>
    ModelCollection ItemsCollection = new ModelCollection();

    private void OnPageScroll(object sender, ScrollViewerViewChangedEventArgs e)
    {
        InnerFlipper.ViewChanged -= OnPageScroll;//Temporarily stop handling this event, to prevent double triggers and let the CPU breath for a little

       int FlipViewerRealIndex = GetFlipViewIndex(sender);

        ItemsCollection.UpdatePages(FlipViewerRealIndex);

        InnerFlipper.ViewChanged += OnPageScroll;//Start getting this event again, ready for the next iteration
    }

    /// <summary>
    /// No idea why, FlipView's inner offset starts at 2. Fuck it, subtract 2 and it works fine.
    /// </summary>
    /// <param name="sender"></param>
    /// <returns></returns>
    public static int GetFlipViewIndex(object sender)
    {
        double CorrectedScrollOffset= ((ScrollViewer)sender).HorizontalOffset - 2;
        int NewIndex = (int)Math.Round(CorrectedScrollOffset);//Round instead of simple cast, otherwise there is a bias in the direction

        return NewIndex;
    }

在我们拥有的模型集合设置上。

    private const int VirtualListRadius = 1000;
    /// <summary>
    /// The collection constructor, runs the first step of the data filling.
    /// </summary>
    public ModelCollection()
    {
        //Fill in the virtual list with the default (mostly null) custom control.
        for (int i = 1; i <= VirtualListRadius; i++)
        {
            object LeftMostPage = NewPageControl(args1);
            object RightMostPage = NewPageControl(args2);
            Items.Insert(0, LeftMostPage);
            Items.Add(RightMostPage);
        }
    }        

    /// <summary>
    /// The FlipViewer's items list, with all the virtual content and real content (where applicable)
    /// </summary>
    public ObservableCollection<Object> Items
    {
        get { return _items; }
        set { SetProperty(ref _items, value); }
    }
    public ObservableCollection<Object> _items = new ObservableCollection<Object>();

更新页面的代码:

/// <summary>
    /// How many pages of content should be buffered in each direction
    /// </summary>
    private const int ObservableListRadius = 3;

    /// <summary>
    /// The main update function that replaces placeholder-virtual content with actual content, while freeing up content that's no longe necessary
    /// </summary>
    /// <param name="scrollIndex">The new index absolute index that should be extracted from the Flipview's inner scroller</param>
    public void UpdatePages(int scrollIndex)
    {
        if (scrollIndex < 0 || scrollIndex > Items.Count - 1)
        {
            //If the scroll has move beyond the virtual list, then we're in trouble
            throw new Exception("The scroll has move beyond the virtual list");
        }

        int MinIndex = Math.Max(scrollIndex - ObservableListRadius, 0);
        int MaxIndex = Math.Min(scrollIndex + ObservableListRadius, Items.Count() - 1);

        //Update index content
        (Items.ElementAt(scrollIndex) as ModelPage).UpdatePage(args1);

        Status = Enumerators.CollectionStatusType.FirstPageLoaded;

        //Update increasing radius indexes
        for (int radius = 1; radius <= Constants.ObservableListRadius; radius++)
        {
            if (scrollIndex + radius <= MaxIndex && scrollIndex + radius > MinIndex)
            {
                (Items.ElementAt(scrollIndex + radius) as ModelPage).UpdatePage(args2);
            }

            if (scrollIndex - radius >= MinIndex && scrollIndex - radius <= MaxIndex)
            {
                (Items.ElementAt(scrollIndex - radius) as ModelPage).UpdatePage(args3);
            }

        }     
    }
于 2014-06-16T10:30:35.717 回答