博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(二)
阅读量:6212 次
发布时间:2019-06-21

本文共 12703 字,大约阅读时间需要 42 分钟。

原文:

上篇 讲到该控件的需要和设计过程。

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

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

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

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

public IAsyncOperation
LoadMoreItemsAsync(uint count) { IAsyncOperation
result = rowAdapter.LoadMoreItemsAsync(count); if (rowAdapter.Count > 0) { for (int i = this.Count; i < rowAdapter.Count; i++) { if (rowAdapter.SourceList.Count / rowAdapter.rowItemsCount > i) { var item = this.ElementAtOrDefault(i); if (item == null) { this.Insert(i, rowAdapter[i]); } } } } return result; }

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

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

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

public bool HasMoreItems        {            get            {                var hasMoreItems = rowAdapter.HasMoreItems;                   if (!hasMoreItems)                {                    if (rowAdapter.Count > 0 && this.Count < rowAdapter.Count)                    {                        for (int i = this.Count; i < rowAdapter.Count; i++)                        {                            //sometime it will miss some indexs in LoadMoreItemsAsync method,                            //if hasMoreItems is false, that means not more items,                            //so at that monment we should add the missed items.                            //if (rowAdapter.SourceList.Count / rowAdapter.rowItemsCount <= i)                            {                                var item = this.ElementAtOrDefault(i);                                if (item == null)                                {                                    this.Insert(i, rowAdapter[i]);                                }                            }                        }                    }                }                return hasMoreItems;            }        }

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

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

public class ResizeableItems : List<ResizeableItem>

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

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

list = new List
(); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); var c1 = new ResizeableItem() { Columns = 2, Items = list, Min = windowMinwidth + +1, Max = windowMinwidth + rangwidth * 1 }; _resizeableItems.Add(c1);

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

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

_resizeableItems = new ResizeableItems();                //ApplicationView.GetForCurrentView().SetPreferredMinSize(new Windows.Foundation.Size(200, 200));                double windowMinwidth = 500;                double windowMaxwidth = DeviceInfo.DeviceScreenSize.Width;                double rangwidth = (windowMaxwidth - windowMinwidth) / 4.0;                #region 4                var list = new List
(); list.Add(new Resizable() { Width = 2, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); var c4 = new ResizeableItem() { Columns = 4, Items = list, Min = windowMinwidth + rangwidth * 3 + 1, Max = double.PositiveInfinity }; _resizeableItems.Add(c4); #endregion #region 3 list = new List
(); list.Add(new Resizable() { Width = 2, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); var c3 = new ResizeableItem() { Columns = 3, Items = list, Min = windowMinwidth + rangwidth * 2 + 1, Max = windowMinwidth + rangwidth * 3 }; _resizeableItems.Add(c3); #endregion #region 2 list = new List
(); list.Add(new Resizable() { Width = 2, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 2 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); list.Add(new Resizable() { Width = 1, Height = 1 }); var c2 = new ResizeableItem() { Columns = 2, Items = list, Min = windowMinwidth + rangwidth * 1 + 1, Max = windowMinwidth + rangwidth * 2 }; _resizeableItems.Add(c2); #endregion #region 1 list = new List
(); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); list.Add(new Resizable() { Width = 2, Height = 1 }); var c1 = new ResizeableItem() { Columns = 2, Items = list, Min = windowMinwidth + +1, Max = windowMinwidth + rangwidth * 1 }; _resizeableItems.Add(c1); #endregion
View Code

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

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

protected override Size MeasureOverride(Size availableSize)        {            if (!PlatformIndependent.IsWindowsPhoneDevice)            {                OnMeasureOverride(availableSize);            }            return base.MeasureOverride(availableSize);        }                 private void OnMeasureOverride(Size availableSize)        {            if (ItemsSource != null && ItemsSource is IResizeableItems && availableSize != Size.Empty)            {                var resizeableItem = ResizeableItems.GetItem(availableSize.Width);                if (resizeableItem != null)                {                    resizeableItem.ItemWidth = (int)(availableSize.Width / resizeableItem.Columns - 7);                    foreach (var item in this.Items)                    {                        var gridviewItem = this.ContainerFromItem(item) as ListViewItem;                        //not null, it's in viewport, so it need to update.                        if (gridviewItem != null && gridviewItem.ContentTemplateRoot != null)                        {                            var gridview = gridviewItem.ContentTemplateRoot as VariableSizedGridView;                            gridview.ResizeableItem = null;                            gridview.ResizeableItem = resizeableItem;                        }                    }                }            }        }

 

3.ListViewItem默认模板的修改

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

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

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

Default style

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

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

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

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

 

总结:

虽然说这个控件已经满足了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这种情况进行了处理。

private void ObservableRowAapter_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)        {            switch (e.Action)            {                case NotifyCollectionChangedAction.Add:                    break;                case NotifyCollectionChangedAction.Move:                    break;                case NotifyCollectionChangedAction.Remove:                    break;                case NotifyCollectionChangedAction.Replace:                    break;                case NotifyCollectionChangedAction.Reset:                    if (this.Count>0)                    {                        this.Clear();                    }                    break;                default:                    break;            }        }

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

为了部落!

开源有益,

转载地址:http://mgdja.baihongyu.com/

你可能感兴趣的文章
一个字符串小题目
查看>>
SharePoint Server中的用户信息管理
查看>>
SCOM 2012系列②安装部署SCOM
查看>>
WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)所有webapi似乎都缺失的一个功能...
查看>>
ASP.NET MVC4+BootStrap 实战(四)
查看>>
构建基于Hibernate的servlet(1)
查看>>
[IE技巧] IE的 "已终止操作" (Operation Aborted) 之谜
查看>>
综合应用WPF/WCF/WF/LINQ之四:创建一个StateMachineWorkflow
查看>>
负载均衡连载之五
查看>>
iOS应用开发之CoreData[转]
查看>>
分享文件一个上传工具类
查看>>
覆盖索引或列包含
查看>>
总结了一些常见的排序算法,面试必备啊!
查看>>
【问题&解决】SQL2008 SQL Server身份认证方式登录失败(错误18456)解决方法图解...
查看>>
SQL Server 数据库设计规范
查看>>
090923 T 一个对象一对多关联的问题
查看>>
在Heroku上部署Node.js
查看>>
BDB c++例子,从源码编译到运行
查看>>
1488: C语言实验题――买糖果
查看>>
OLEDB 命令转换组件的用法
查看>>