上篇UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(一) 讲到该控件的需要和设计过程。

这篇讲讲开发过程中一些重要问题解决。

1.支持ISupportIncrementalLoading,实现HasMoreItems属性和LoadMoreItemsAsync方法

因为我们上篇里面讲过,需要把源数据分成一个一个的Group作为GirdView的源,

所以LoadMoreItemsAsync方法里面我做了以下的实现:

  1. public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
  2. {
  3. IAsyncOperation<LoadMoreItemsResult> result = rowAdapter.LoadMoreItemsAsync(count);
  4. if (rowAdapter.Count > )
  5. {
  6. for (int i = this.Count; i < rowAdapter.Count; i++)
  7. {
  8. if (rowAdapter.SourceList.Count / rowAdapter.rowItemsCount > i)
  9. {
  10. var item = this.ElementAtOrDefault(i);
  11. if (item == null)
  12. {
  13. this.Insert(i, rowAdapter[i]);
  14. }
  15. }
  16. }
  17. }
  18.  
  19. return result;
  20. }

应该还是比较清楚的,当源数据里面的个数超过了RowItemsCount的时候,我们才插入Item。

也就是说。当满15个Item的时候我们才插入第1个Row Item,当满30个Item的时候我们插入第2个Row Item......

可能有人会说,如果源数据不是15个整数,那怎么办呢??嗯,我也遇到了这个问题,当然,HasMoreItems属性也需要作相应的实现

  1. public bool HasMoreItems
  2. {
  3. get
  4. {
  5. var hasMoreItems = rowAdapter.HasMoreItems;
  6.  
  7. if (!hasMoreItems)
  8. {
  9. if (rowAdapter.Count > && this.Count < rowAdapter.Count)
  10. {
  11. for (int i = this.Count; i < rowAdapter.Count; i++)
  12. {
  13. //sometime it will miss some indexs in LoadMoreItemsAsync method,
  14. //if hasMoreItems is false, that means not more items,
  15. //so at that monment we should add the missed items.
  16. //if (rowAdapter.SourceList.Count / rowAdapter.rowItemsCount <= i)
  17. {
  18. var item = this.ElementAtOrDefault(i);
  19. if (item == null)
  20. {
  21. this.Insert(i, rowAdapter[i]);
  22. }
  23. }
  24. }
  25. }
  26. }
  27. return hasMoreItems;
  28. }
  29. }

当HasMoreItems为false的时候,就是说这个源不会有更多的数据了,所以这时候我们应该把剩余的Item都加入到下一个Row Item里面去。

2.当Window size 改变的时候,实现不同的可变大小结构。

public class ResizeableItems : List<ResizeableItem>

每一种结构,我用一个ResizeableItem来表示。

比如window 最小的时候这种结构。

  1. list = new List<Resizable>();
  2. list.Add(new Resizable() { Width = , Height = });
  3. list.Add(new Resizable() { Width = , Height = });
  4. list.Add(new Resizable() { Width = , Height = });
  5. list.Add(new Resizable() { Width = , Height = });
  6. list.Add(new Resizable() { Width = , Height = });
  7. list.Add(new Resizable() { Width = , Height = });
  8. list.Add(new Resizable() { Width = , Height = });
  9. list.Add(new Resizable() { Width = , Height = });
  10. list.Add(new Resizable() { Width = , Height = });
  11. list.Add(new Resizable() { Width = , Height = });
  12. list.Add(new Resizable() { Width = , Height = });
  13. list.Add(new Resizable() { Width = , Height = });
  14. list.Add(new Resizable() { Width = , Height = });
  15. list.Add(new Resizable() { Width = , Height = });
  16. list.Add(new Resizable() { Width = , Height = });
  17.  
  18. var c1 = new ResizeableItem() { Columns = , Items = list, Min = windowMinwidth + +, Max = windowMinwidth + rangwidth * };
  19. _resizeableItems.Add(c1);

设置GirdView里面的每个Item的宽高比2:1,设置ResizeableItem的最小和最大值,这个意思就是当window 到达MIn和Max的这个区间的时候就使用这个结构。

然后也设置出其它的结构样式。(PS:我这里还没找到Get 最小window 宽度的办法,好像只能设置,如果有办法的朋友请留言一下)

  1. _resizeableItems = new ResizeableItems();
  2.  
  3. //ApplicationView.GetForCurrentView().SetPreferredMinSize(new Windows.Foundation.Size(200, 200));
  4.  
  5. double windowMinwidth = ;
  6. double windowMaxwidth = DeviceInfo.DeviceScreenSize.Width;
  7. double rangwidth = (windowMaxwidth - windowMinwidth) / 4.0;
  8.  
  9. #region 4
  10. var list = new List<Resizable>();
  11. list.Add(new Resizable() { Width = , Height = });
  12. list.Add(new Resizable() { Width = , Height = });
  13. list.Add(new Resizable() { Width = , Height = });
  14. list.Add(new Resizable() { Width = , Height = });
  15. list.Add(new Resizable() { Width = , Height = });
  16. list.Add(new Resizable() { Width = , Height = });
  17. list.Add(new Resizable() { Width = , Height = });
  18. list.Add(new Resizable() { Width = , Height = });
  19. list.Add(new Resizable() { Width = , Height = });
  20. list.Add(new Resizable() { Width = , Height = });
  21. list.Add(new Resizable() { Width = , Height = });
  22. list.Add(new Resizable() { Width = , Height = });
  23. list.Add(new Resizable() { Width = , Height = });
  24. list.Add(new Resizable() { Width = , Height = });
  25. list.Add(new Resizable() { Width = , Height = });
  26.  
  27. var c4 = new ResizeableItem() { Columns = , Items = list, Min = windowMinwidth + rangwidth * + , Max = double.PositiveInfinity };
  28. _resizeableItems.Add(c4);
  29. #endregion
  30.  
  31. #region 3
  32. list = new List<Resizable>();
  33. list.Add(new Resizable() { Width = , Height = });
  34. list.Add(new Resizable() { Width = , Height = });
  35. list.Add(new Resizable() { Width = , Height = });
  36. list.Add(new Resizable() { Width = , Height = });
  37. list.Add(new Resizable() { Width = , Height = });
  38. list.Add(new Resizable() { Width = , Height = });
  39. list.Add(new Resizable() { Width = , Height = });
  40. list.Add(new Resizable() { Width = , Height = });
  41. list.Add(new Resizable() { Width = , Height = });
  42. list.Add(new Resizable() { Width = , Height = });
  43. list.Add(new Resizable() { Width = , Height = });
  44. list.Add(new Resizable() { Width = , Height = });
  45. list.Add(new Resizable() { Width = , Height = });
  46. list.Add(new Resizable() { Width = , Height = });
  47. list.Add(new Resizable() { Width = , Height = });
  48.  
  49. var c3 = new ResizeableItem() { Columns = , Items = list, Min = windowMinwidth + rangwidth * + , Max = windowMinwidth + rangwidth * };
  50. _resizeableItems.Add(c3);
  51. #endregion
  52.  
  53. #region 2
  54. list = new List<Resizable>();
  55. list.Add(new Resizable() { Width = , Height = });
  56. list.Add(new Resizable() { Width = , Height = });
  57. list.Add(new Resizable() { Width = , Height = });
  58. list.Add(new Resizable() { Width = , Height = });
  59. list.Add(new Resizable() { Width = , Height = });
  60. list.Add(new Resizable() { Width = , Height = });
  61. list.Add(new Resizable() { Width = , Height = });
  62. list.Add(new Resizable() { Width = , Height = });
  63. list.Add(new Resizable() { Width = , Height = });
  64. list.Add(new Resizable() { Width = , Height = });
  65. list.Add(new Resizable() { Width = , Height = });
  66. list.Add(new Resizable() { Width = , Height = });
  67. list.Add(new Resizable() { Width = , Height = });
  68. list.Add(new Resizable() { Width = , Height = });
  69. list.Add(new Resizable() { Width = , Height = });
  70.  
  71. var c2 = new ResizeableItem() { Columns = , Items = list, Min = windowMinwidth + rangwidth * + , Max = windowMinwidth + rangwidth * };
  72. _resizeableItems.Add(c2);
  73. #endregion
  74.  
  75. #region 1
  76. list = new List<Resizable>();
  77. list.Add(new Resizable() { Width = , Height = });
  78. list.Add(new Resizable() { Width = , Height = });
  79. list.Add(new Resizable() { Width = , Height = });
  80. list.Add(new Resizable() { Width = , Height = });
  81. list.Add(new Resizable() { Width = , Height = });
  82. list.Add(new Resizable() { Width = , Height = });
  83. list.Add(new Resizable() { Width = , Height = });
  84. list.Add(new Resizable() { Width = , Height = });
  85. list.Add(new Resizable() { Width = , Height = });
  86. list.Add(new Resizable() { Width = , Height = });
  87. list.Add(new Resizable() { Width = , Height = });
  88. list.Add(new Resizable() { Width = , Height = });
  89. list.Add(new Resizable() { Width = , Height = });
  90. list.Add(new Resizable() { Width = , Height = });
  91. list.Add(new Resizable() { Width = , Height = });
  92.  
  93. var c1 = new ResizeableItem() { Columns = , Items = list, Min = windowMinwidth + +, Max = windowMinwidth + rangwidth * };
  94. _resizeableItems.Add(c1);
  95. #endregion

这样我们就设置好了,到达多少size的时候使用什么结构模板了。。

最后我们只需要在控件的MeasureOverrid中去设置,GridView的Item的样式就好了.

  1. protected override Size MeasureOverride(Size availableSize)
  2. {
  3. if (!PlatformIndependent.IsWindowsPhoneDevice)
  4. {
  5. OnMeasureOverride(availableSize);
  6. }
  7. return base.MeasureOverride(availableSize);
  8. }
  9.  
  10. private void OnMeasureOverride(Size availableSize)
  11. {
  12. if (ItemsSource != null && ItemsSource is IResizeableItems && availableSize != Size.Empty)
  13. {
  14. var resizeableItem = ResizeableItems.GetItem(availableSize.Width);
  15.  
  16. if (resizeableItem != null)
  17. {
  18. resizeableItem.ItemWidth = (int)(availableSize.Width / resizeableItem.Columns - );
  19.  
  20. foreach (var item in this.Items)
  21. {
  22. var gridviewItem = this.ContainerFromItem(item) as ListViewItem;
  23. //not null, it's in viewport, so it need to update.
  24. if (gridviewItem != null && gridviewItem.ContentTemplateRoot != null)
  25. {
  26. var gridview = gridviewItem.ContentTemplateRoot as VariableSizedGridView;
  27. gridview.ResizeableItem = null;
  28. gridview.ResizeableItem = resizeableItem;
  29.  
  30. }
  31. }
  32. }
  33.  
  34. }
  35. }

3.ListViewItem默认模板的修改
在使用这个的时候因为其实是个ListView,所以当你点击到GridView外面的时候就点击到了ListLViewItem上面,会有些你不想要的效果,比如PointerDown。

第一次用VS拿到ListViewItem的模板的时候发现没地方可能修改这个动画呢???

再查了下MSDN,发现原来,ListViewItem是有2套模板的,

Default style

When the ListView's ItemsPanel is an ItemsStackPanel (the default) or ItemsWrapGrid, this template is used to show the data items. This template uses aListViewItemPresenter instead of a UIElement tree to improve grid performance.

这个模板跟我从VS里面拿到的是一样的。

  1. <!-- Default style for Windows.UI.Xaml.Controls.ListViewItem -->
  2. <Style TargetType="ListViewItem">
  3. <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
  4. <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
  5. <Setter Property="Background" Value="Transparent"/>
  6. <Setter Property="TabNavigation" Value="Local"/>
  7. <Setter Property="IsHoldingEnabled" Value="True"/>
  8. <Setter Property="Margin" Value="0,0,18,2"/>
  9. <Setter Property="HorizontalContentAlignment" Value="Left"/>
  10. <Setter Property="VerticalContentAlignment" Value="Top"/>
  11. <Setter Property="Template">
  12. <Setter.Value>
  13. <ControlTemplate TargetType="ListViewItem">
  14. <ListViewItemPresenter
  15. ContentTransitions="{TemplateBinding ContentTransitions}"
  16. Padding="{TemplateBinding Padding}"
  17. SelectionCheckMarkVisualEnabled="True"
  18. CheckHintBrush="{ThemeResource ListViewItemCheckHintThemeBrush}"
  19. CheckSelectingBrush="{ThemeResource ListViewItemCheckSelectingThemeBrush}"
  20. CheckBrush="{ThemeResource ListViewItemCheckThemeBrush}"
  21. DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}"
  22. DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}"
  23. FocusBorderBrush="{ThemeResource ListViewItemFocusBorderThemeBrush}"
  24. PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"
  25. PointerOverBackground="{ThemeResource ListViewItemPointerOverBackgroundThemeBrush}"
  26. SelectedBorderThickness="{ThemeResource ListViewItemCompactSelectedBorderThemeThickness}"
  27. SelectedBackground="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}"
  28. SelectedForeground="{ThemeResource ListViewItemSelectedForegroundThemeBrush}"
  29. SelectedPointerOverBackground="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}"
  30. SelectedPointerOverBorderBrush="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}"
  31. DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
  32. DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
  33. ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
  34. HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
  35. VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
  36. PointerOverBackgroundMargin=""
  37. ContentMargin="" />
  38. </ControlTemplate>
  39. </Setter.Value>
  40. </Setter>
  41. </Style>

When the ListView's ItemsPanel is not an ItemsStackPanel (the default) or ItemsWrapGrid, this template is used to show the data items. This template uses aUIElement tree and visual states instead of a ListViewItemPresenter.

这个模板我就不贴了,比较多,MSDN地址

总结:

虽然说这个控件已经满足了Boss的需求,但是我还是觉得有一些需要改进的。

1.UI Virtualized

如果说GridView里面的Item个数被用户设置的很多,这个必定是很占用内存的。

实际Debug,也发现,Live Visual Tree里面有3个ListViewItem.

感觉内存中不需要这么多个ListViewItem 来循环回收利用,我的猜想是微软做了上下各一个Item的缓存来提高Scrolling的流畅。

但对于这个控件来说,内存里面的UI Item 会有3*15个,因为我们知道VariableSizedWrapGrid是不支持UI虚拟化的。

2.没有对Insert,Delete进行处理。

这个控件还有一个限制,就是源是一个固定个数或者是ISupportIncrementalLoading,如果在过程中add,insert,delete的话,暂时没有进行处理。

只对Reset这种情况进行了处理。

  1. private void ObservableRowAapter_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  2. {
  3. switch (e.Action)
  4. {
  5. case NotifyCollectionChangedAction.Add:
  6. break;
  7. case NotifyCollectionChangedAction.Move:
  8. break;
  9. case NotifyCollectionChangedAction.Remove:
  10. break;
  11. case NotifyCollectionChangedAction.Replace:
  12. break;
  13. case NotifyCollectionChangedAction.Reset:
  14. if (this.Count>)
  15. {
  16. this.Clear();
  17. }
  18. break;
  19. default:
  20. break;
  21. }
  22. }

希望有好想法的童鞋能留言,大家讨论共同进步。。

为了部落!

开源有益,GitHub源代码地址

UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(二)的更多相关文章

  1. UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(一)

    Boss的需要时这样的,Item是可变大小的,同时根据不同的Window size,来确定Item的结构和大小Window 小的时候是 大的时候是这样的: 当然这size变化的过程中也允许其他结构,我 ...

  2. 算法Sedgewick第四版-第1章基础-008一用数组实现栈(泛型、可变大小)

    package algorithms.ADT; /*************************************************************************** ...

  3. Xamarin.Forms 现已开启对 UWP 的支持

    Xamarin.Forms 现已升级到 2.0.0.6482 , 正式开启了对 UWP 的支持. 要创建 UWP 项目, 必须是 VS2015, WIN8.1 下也可以, 但是只有 Windows 1 ...

  4. 关于理解《C++ 对象模型》中:把单一元素的数组放在末尾,struct可以拥有可变大小的数组

    这一章在第19页,写的好深奥,我竟然没看明白在说什么--之后再看了几遍,终于明白了. 原文: C程序员的巧计有时候却成为c++程序员的陷阱.例如把单一元素的数组放在一个struct的末尾,于是每个st ...

  5. 64位平台支持大于2 GB大小的数组

    64位平台支持大于2 GB大小的数组 64位平台.NET Framework数组限制不能超过2GB大小.这种限制对于需要使用到大型矩阵和向量计算的工作人员来说,是一个非常大问题. 无论RAM容量有多大 ...

  6. 移动设备应用程序中支持多个屏幕大小和 DPI 值

    支持多个屏幕大小和 DPI 值的指导原则 要部署独立于平台的应用程序,应了解不同的输出设备.设备可以具有不同的屏幕大小或分辨率以及不同的 DPI 值或密度. Flex 工程师 Jason SJ 在他的 ...

  7. 使struct对象拥有可变大小的数组——(C++深度探索)

    首先摘录<Inside The C++ Object Model>中的一段话: 把单一元素的数组放在一个struct的尾端,于是每个 struct objects 可以拥有可变大小的数组: ...

  8. 0x04 Python logger 支持多进程日志按大小分割

    目录 支持多进程日志按大小分割 多进程日志大小分割handler配置实例 支持多进程日志按大小分割 由于python内置模块logging.handlers.RotatingFileHandler是不 ...

  9. 如何查看自己的电脑 CPU 是否支持硬件虚拟化

    引言 在你安装各种虚拟机之前,应该先测试一下自己的电脑 CPU 是否支持硬件虚拟化. 如果你的电脑比较老旧,可能不支持硬件虚拟化,那么将无法安装虚拟机软件. 如何查看自己 CPU 是否支持硬件虚拟化 ...

随机推荐

  1. cookie操作简单实现

    var Cookie = { get:function(key){ var reg = new RegExp('(?:^| )' + key + '=([^;]+)(?=;|$)','gi'); re ...

  2. web中c#纯网站中引用log4net模块,不记录日志

    如题,解决如下: 1.log4net.config配置如下: <?xml version="1.0" encoding="utf-8" ?> < ...

  3. 室内定位系列(三)——位置指纹法的实现(KNN)

    位置指纹法中最常用的算法是k最近邻(kNN):选取与当前RSS最邻近的k个指纹的位置估计当前位置,简单直观有效.本文介绍kNN用于定位的基本原理与具体实现(matlab.python). 基本原理 位 ...

  4. 【前端攻略】:玩转图片Base64编码

    引言 图片处理在前端工作中可谓占据了很重要的一壁江山.而图片的 base64 编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的 base64 编码.标题略大,不过只是希望通过一些浅显 ...

  5. JPA入门

    JPA是什么 JPA全称Java Persistence API,是一组用于将数据存入数据库的类和方法的集合.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化 ...

  6. 11i和R12配置JAR包

    R11:$IAS_ORACLE_HOME/Apache/Jserv/etc/jserv.properties R12: 方法1:直接解压JAR包放到$JAVA_TOP下: 方法2:编辑:$ORA_CO ...

  7. 求两圆相交部分面积(C++)

    已知两圆圆心坐标和半径,求相交部分面积: #include <iostream> using namespace std; #include<cmath> #include&l ...

  8. java后台对前端输入的特殊字符进行转义

    转自:http://www.cnblogs.com/yangzhilong/p/5667165.html java后台对前端输入的特殊字符进行转义 HTML: 常见的帮助类有2个:一个是spring的 ...

  9. 33个超级有用必须要收藏的PHP代码样例

    作为一个正常的程序员,会好几种语言是十分正常的,相信大部分程序员也都会编写几句PHP程序,如果是WEB程序员,PHP一定是必备的,即使你没用开发过大型软件项目,也一定多少了解它的语法. 在PHP的流行 ...

  10. visual studio installer 打包123

    下载安装visual studio installer