2013-08-16 55 views
0

我想实现一个日历样式(基于日期)无限FlipView用户可以通过触摸滚动。我将FlipViewItemTemplate与自定义ObservableCollection绑定在一起。一切都很好地显示,我操纵ObservableCollection提供所需的行为:当选定的索引更改时,将新元素添加到顶部并从底部删除。无限滚动翻转Flipview在翻转时更新内容

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

问题是,当用户停止滚动FlipView将只触发SelectedIndex更改事件。对于小型刷卡来说,这很好,但用户可以轻松到达集合的末尾,并在收集更新之前走到死胡同。

我已成功订阅了FlipViewScrollViewer[Viewchanged][1],如建议here和我能够看到和使用的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基于指数变化的计算值的多种组合和真正水流偏移等没有给出一个透明的结果,这是一个无缝无限滚动。

任何想法如何避免工件,处理这个事件,甚至其他方式来实现以达到预期的结果?

回答

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); 
      } 

     }  
    } 
+0

你有这方面的一个例子吗? –

+0

一个例子会很棒!我也在为这个寻求解决方案.. – SeBo

+0

添加例子来回答。 – MoDu