2013-08-16 53 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