程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 基於GridView LoadMoreAsync 設計的橫向雙向瀑布流 組件 源碼分享

基於GridView LoadMoreAsync 設計的橫向雙向瀑布流 組件 源碼分享

編輯:C#入門知識

原理: 實現了ISupportIncrementalLoading 接口 完成了增量加載, 針對於本地對象無法釋放的情況 增加了 相關的Func 同時 通過VisualTree 拿到了GridView中 HorizontalBar 來對滾動條的位置進行捕捉 與計算 通過計算後 來執行 虛化操作   如需 轉載請聲明博客作者   以下是源碼:   IncrementalLoadingCollection 對象: [csharp]   public class IncrementalLoadingCollection<T> : ObservableCollection<T>, ISupportIncrementalLoading      {          // 是否正在異步加載中          private bool _isBusy = false;             // 提供數據的 Func          // 第一個參數:增量加載的起始索引;第二個參數:需要獲取的數據量;第三個參數:獲取到的數據集合          private Func<int, int, List<T>> _funcGetData;          // 最大可顯示的數據量          private uint _totalCount = 0;             private Func<T, T> _actDisposeData;             public int PageIndex = 0;             public uint perCount = 0;             /// <summary>          /// 構造函數          /// </summary>          /// <param name="totalCount">最大可顯示的數據量</param>          /// <param name="getDataFunc">提供數據的 Func</param>          public IncrementalLoadingCollection(uint totalCount, Func<int, int, List<T>> getDataFunc, Func<T, T> actDisposeData)          {              _funcGetData = getDataFunc;              _totalCount = totalCount;              _actDisposeData = actDisposeData;          }             /// <summary>          /// 是否還有更多的數據          /// </summary>          public bool HasMoreItems          {              get { return this.Count < _totalCount; }          }             /// <summary>          /// 異步加載數據(增量加載)          /// </summary>          /// <param name="count">需要加載的數據量</param>          /// <returns></returns>          public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)          {              perCount = count;              if (_isBusy)              {                  return AsyncInfo.Run((token) => Task.Run<LoadMoreItemsResult>(() =>                  {                      return new LoadMoreItemsResult { Count = (uint)this.Count };                     }, token));              }              _isBusy = true;                 var dispatcher = Window.Current.Dispatcher;                 return AsyncInfo.Run(                  (token) =>                      Task.Run<LoadMoreItemsResult>(                         async () =>                         {                             try                             {                                 //// 模擬長時任務                                 await Task.Delay(100);                                    // 增量加載的起始索引                                 var startIndex = this.Count;                                    await dispatcher.RunAsync(                                      CoreDispatcherPriority.Normal,                                      () =>                                      {                                          PageIndex++;                                          // 通過 Func 獲取增量數據                                          var items = _funcGetData(startIndex, (int)count);                                          if (items != null)                                              foreach (var item in items)                                              {                                                  this.Add(item);                                              }                                      });                                    // Count - 實際已加載的數據量                                 return new LoadMoreItemsResult { Count = (uint)this.Count };                             }                             finally                             {                                 _isBusy = false;                             }                         },                         token));          }             public void DisposeItemByStartAndEnd(long start, long end)          {              for (long i = start; i < end; i++)              {                  _actDisposeData(this.Items[(int)i]);              }          }             public void RemoveItemByRange(long start, long end)          {              for (long i = start; i < end; i++)              {                  if (this.Items.Count > i)                  {                      this.RemoveItem((int)i);                  }              }          }             public void Reset()          {              this.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));          }      }     IncrementalLoadingGridView:   [csharp]   public class IncrementalLoadingGridView : GridView     {         #region Member Variables         private ScrollBar _HorizontalScrollBar;         private Dictionary<int, int> _pageOffsetDict = new Dictionary<int, int>();         private Dictionary<int, bool> _pageVirtualizingDict = new Dictionary<int, bool>();         private dynamic _filelist;         #endregion           #region Constants         const string HORIZONTALSCROLLBAR_PARTNAME = "HorizontalScrollBar";         #endregion            public IncrementalLoadingGridView()         {             this.Loaded += ((sender, e) =>             {                 this.OnApplyTemplate();             });             this.Unloaded += ((sender, e) =>             {                 _HorizontalScrollBar = Pollute.FindVisualChildByName<ScrollBar>(this, HORIZONTALSCROLLBAR_PARTNAME);                 if (null != _HorizontalScrollBar)                     _HorizontalScrollBar.ValueChanged -= ValueChanged;             });            }            protected override async void OnApplyTemplate()         {             base.OnApplyTemplate();                await this.WaitForLayoutUpdateAsync();             _HorizontalScrollBar = Pollute.FindVisualChildByName<ScrollBar>(this, HORIZONTALSCROLLBAR_PARTNAME);             if (null != _HorizontalScrollBar)             {                 _HorizontalScrollBar.ValueChanged += ValueChanged;             }         }            protected override async void OnItemsChanged(object e)         {             if (null != this.ItemsSource)             {                 InitPositionByValue();             }                base.OnItemsChanged(e);             if (null == this.ItemsSource)             {                 await this.WaitForLoadedAsync();                 InitPositionByValue();             }         }            private void InitPositionByValue()         {             _filelist = this.ItemsSource;             CompositionTarget.Rendering += ((obj, args) =>             {                 var newValue = Convert.ToInt32(_HorizontalScrollBar.Value);                 int currentPageIndex = _filelist.PageIndex - 2;                 if (!_pageOffsetDict.ContainsKey(currentPageIndex))                 {                     _pageOffsetDict[currentPageIndex] = newValue;                     _pageVirtualizingDict[currentPageIndex] = false;                 }             });         }            private int preIndex = 0;         private int maxPageIndex = 0;         private int minOffset;         private async void ValueChanged(object sender, RangeBaseValueChangedEventArgs e)         {             if (null == this.ItemsSource) return;             var newValue = Convert.ToInt32(e.NewValue);             var oldValue = Convert.ToInt32(e.OldValue);             if (newValue == oldValue) return;             Debug.WriteLine("坐標:" + newValue);             int currentPageIndex;             if (null == _filelist) _filelist = this.ItemsSource;             if (e.NewValue < 1.0)             {                 await Task.Run(async () =>                 {                     string text = "滑到頭了 開始釋放 釋放前個數:" + _filelist.Count.ToString();                     Debug.WriteLine(text);                     for (int i = 3; i < maxPageIndex; i++)                     {                         _pageVirtualizingDict[i] = true;                         var start = (i - 1) * _filelist.perCount;                         var end = i * _filelist.perCount - 1;                         await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>                         {                             if (_filelist.Count > end)                             {                                 _filelist.DisposeItemByStartAndEnd(start, end);                                 _filelist.RemoveItemByRange(start, end);                             }                             await Task.Delay(500);                             _filelist.Reset();                         });                     }                     _filelist.PageIndex = 2;                     text = "滑到頭了 釋放完畢 釋放後個數:" + _filelist.Count;                        Debug.WriteLine(text);                 });             }             else                 await Task.Run(() =>                 {                     if (newValue > oldValue)                     {                         //lock (_pageOffsetDict)                         //{                         var horiOffset = newValue - oldValue;                         if (minOffset > horiOffset) minOffset = horiOffset;                         currentPageIndex = _filelist.PageIndex - 2;                         //_pageOffsetDict[currentPageIndex] = newValue;                         maxPageIndex = Convert.ToInt32(_filelist.Count) / Convert.ToInt32(_filelist.perCount);                            //}                         if (preIndex != currentPageIndex && _pageOffsetDict.ContainsValue(newValue))                         {                             Debug.WriteLine("坐標:" + newValue + " 上一頁:" + preIndex + " 當前頁:" + currentPageIndex);                             if (_pageVirtualizingDict.ContainsKey(preIndex))                             {                                 _pageVirtualizingDict[preIndex] = false;                                 Debug.WriteLine("@@@@@@@@@@@@@@@@@@@@@@@@@需要向後虛化:" + preIndex + "@@@@@@@@@@@@@@@@@@@@@@" + _pageVirtualizingDict[preIndex]);                                 if (!_pageVirtualizingDict[preIndex] && preIndex > 3)                                 {                                     int i = preIndex;                                     while (i > 3)                                     {                                         //if (!_pageVirtualizingDict.ContainsKey(i))                                         //{                                         //    _pageVirtualizingDict[i] = false;                                         //    _pageOffsetDict[i] = oldValue -= minOffset;                                         //}                                         if (_pageVirtualizingDict.ContainsKey(i) && !_pageVirtualizingDict[i])                                         {                                             var start = (i - 3) * _filelist.perCount;                                             var end = (i - 2) * _filelist.perCount - 1;                                             _filelist.DisposeItemByStartAndEnd(start, end);                                             _pageVirtualizingDict[i] = true;                                             Debug.WriteLine("虛化完畢:" + i);                                         }                                         i--;                                     }                                 }                             }                             preIndex = currentPageIndex;                         }                         _pageVirtualizingDict[currentPageIndex] = false;                     }                     else if (newValue < oldValue)                     {                         if (_pageOffsetDict.ContainsValue(newValue))                         {                             currentPageIndex = _pageOffsetDict.GetKey(newValue).FirstOrDefault();                             Debug.WriteLine("當前頁:" + currentPageIndex + " 坐標:" + newValue);                             var offset = 3;                             if (preIndex - offset > currentPageIndex && currentPageIndex > 0)                             {                                 _pageVirtualizingDict[preIndex] = false;                                 if (!_pageVirtualizingDict[preIndex])                                 {                                     Debug.WriteLine("@@@@@@@@@@@@@@@@@@@@@@@@@虛化 After頁:" + preIndex + " 是否虛化" + _pageVirtualizingDict[preIndex]);                                     int i = preIndex - offset;                                     while (i <= maxPageIndex)                                     {                                         //if (!_pageVirtualizingDict.ContainsKey(i))                                         //{                                         //    _pageVirtualizingDict[i] = false;                                         //    _pageOffsetDict[i] = oldValue += minOffset;                                         //}                                         if (_pageVirtualizingDict.ContainsKey(i) && !_pageVirtualizingDict[i])                                         {                                             Debug.WriteLine("開始釋放第:" + i + "頁");                                             int count = _filelist.Count;                                             Debug.WriteLine("虛化前個數:" + count);                                             var start = (i - 1) * _filelist.perCount;                                             var end = i * _filelist.perCount - 1;                                             if (end < _filelist.Count)                                             {                                                 _filelist.DisposeItemByStartAndEnd(start, end);                                             }                                             string writeLine = "虛化after完畢 虛化位Start:" + start + " End:" + end + " Page:" + i + " 虛化後個數:" + count;                                             Debug.WriteLine(writeLine);                                             _pageVirtualizingDict[i] = true;                                         }                                         i++;                                     }                                 }                                 _pageVirtualizingDict[currentPageIndex] = false;                                 //_pageVirtualizingDict[currentPageIndex - 1] = false;                                 //_pageVirtualizingDict[currentPageIndex - 2] = false;                                 //_pageVirtualizingDict[currentPageIndex - 3] = false;                                 preIndex = currentPageIndex;                             }                             _pageVirtualizingDict[currentPageIndex] = false;                         }                     }                    });             if (e.NewValue == _HorizontalScrollBar.Maximum)             {                 this.IsHitTestVisible = false;                 await Task.Delay(500);                 this.IsHitTestVisible = true;             }         }     }     使用方式: [html  <toolkit:IncrementalLoadingGridView x:Name="gvMain"                     Visibility="{Binding IsLeafLevel, Converter={StaticResource BooleanToVisibilityConverter}}"                     Padding="140,40,0,0"                     SelectionMode="None"                     ItemsSource="{Binding ImageItemsSource, Mode=TwoWay}"                     IncrementalLoadingThreshold="0.5" DataFetchSize="0.5"                     IsItemClickEnabled="True"                     PointerMoved="gvMain_PointerMoved"                     ItemClick="gvMain_ItemClick"                    ItemTemplateSelector="{StaticResource imageDataTemplateSelector}">               <GridView.ItemsPanel>                   <ItemsPanelTemplate>                       <WrapGrid VirtualizingStackPanel.VirtualizationMode="Recycling"></WrapGrid>                   </ItemsPanelTemplate>               </GridView.ItemsPanel>           </toolkit:IncrementalLoadingGridView>     IncrementalLoadingThreshold="0.5" DataFetchSize="0.5" 這2個閥值設定的比較低 這樣虛化起來效率會高一些   需要binding 的列表對象 Dispose方法 需要binding對象繼承IDispose 釋放本地流 [csharp  _filelist = new IncrementalLoadingCollection<FileItem>((uint)_currentfiles.Count, (startIndex, Count) =>               {                   SetLoadingState(true);                   if (_currentfiles == null || _currentfiles.Count <= startIndex) return null;                   List<FileItem> list = new List<FileItem>();                   foreach (var file in _currentfiles.Skip(startIndex).Take(Count))                   {                       FileItem item = new FileItem();                       item.File = file;                       item.Name = file.DisplayName;                       if (folder.Name.EndsWith("zhx")) item.Name = "zhx" + item.Name;                       list.Add(item);                   }                   SetLoadingState(false);                   return list;               }, (o) =>               {                   o.Dispose();                   return o;               });    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved