Windows phone UI虚拟化和数据虚拟化(二)
书接上回的Windows phone UI虚拟化和数据虚拟化(一)我们学习了wp的ui虚拟化。
今天来和大家分享一下wp的数据虚拟化。
并同时感谢我的同事dgwutao在编写此文时给我的巨大帮助,3ks!
1.什么是数据虚拟化及其优点。
--弱水三千,只取一瓢饮。百万记录,只载十几条。
和ui虚拟化一样,尽管我们要显示的数据有成百上千条,但我们只在内存中,加载我们需要展示在屏幕上的
若干条。随着列表的滑动,我们添加将要显示在屏幕上的数据条目,删除已经不再展示区的条目。保证内存中
加载的数据条目只有很少的一部分(具体数目根据情况定制)。
虚拟化的优点也显而易见了,有效地节省内存。
2.怎么实现数据虚拟化
不知道各位看到这里,心里会不会说,通过上面的描述,这个,这个,不就是【点击】/【滑动】 加载更多吗?
话说滑动加载真心弱爆了。。。也不要纠结怎么判断触底没触底了。
来!开始我们的数据虚拟化!
接着用上一篇的Demo,我们来看一个基本的列表数据绑定。
【.xaml】
<phone:LongListSelector
ItemsSource="{Binding ListProduct}"
【.cs】

这个是,我们通常的用法。没有任何问题。但是,我们要实现我们想要的只加载屏幕上显示的一页(9条)数据。
该如何着手呢?保持List只有9条很容易,但是当list只有9条恰好一页的时候,我们知道ListBox,LLS的滚动条。
根本就不会滚动。因为列表控件认为你的数据源不是1000条,而是9条。
那么列表控件是根据什么来判断数据源的总数呢?
开始思考。。。3 。。。 2。。。。。1。。。对,答案就是集合的【Count】属性。
所以我们第一步要做的就是,骗过这些列表控件。给他们一个"假的" 【Count】属性
下面我们定义一个泛型类,继承Ilist<T>等几个接口。
public
class
VirtualizingCollection<T>:IList<T>,IList, INotifyPropertyChanged, INotifyCollectionChanged
{
public VirtualizingCollection(int count)
{
this.count = count;
}
public
int Count
{
get { return count; }
set
{
count = value;
RaisePropertyChanged("Count");
}
}
public T this[int index]
{
get
{
Return null;
}
set
{
throw
new
NotImplementedException();
}
}
//----省略-----
}
So Easy! 我们只要在VirtualizingCollection初始化的时候给Count付个1000,就轻松的骗过那些傻傻的列表控件,可以尽情的滚动了。
尽管能刷刷的滚动了,但是我们发现,界面上一片空白,没有任何数据。为啥呢?
控件在绑定后,遍历数据源时。我们的索引 public T this[int index]还没有实现!肯定是不会返回任何数据的。
这块索引的实现并不是固定的实现方式,要根据具体的场景来看。
好,现在我们来假设这样一个qq聊天的场景。
在进入qq会话页面的时候会从本地数据库里读取聊天的历史记录。共有1000条记录。每页显示9条。
这里我们可以按照传统的分页方式来加载。
在上面的类里,我们新建一个字典字段。
private
readonly
Dictionary<int, IList<T>> _pages = new
Dictionary<int, IList<T>>();
这个字典就是我们所说的,对应屏幕上显示的若干条数据(此例中我们保持每个时刻,内存中只有3-5屏数据)
Dictionary<int, IList<T>>
int就是pageindex 页码, IList<T>
就是这一页里的pagesize条数据(本例是9条)
下面是具体的代码
private
readonly
int _pageSize = 9;
public T this[int index]
{
get
{
int pageIndex = index / PageSize;//请求的item的索引(index)所在的页码
int pageOffset = index % PageSize;//滑动列表当前页产生的偏移
RequestPage(pageIndex);
//大于一屏的一半加载下一页
if (pageOffset > PageSize / 2 && pageIndex < Count / PageSize)
{
RequestPage(pageIndex + 1);
}
// 小于一屏的一半加载上一页
if (pageOffset < PageSize / 2 && pageIndex > 0)
{
RequestPage(pageIndex - 1);
}
//只保留,当前页和上下两页,删除多余的
if (_pages.Count >= 3 && _pages.ContainsKey(pageIndex - 2))
{
_pages.Remove(pageIndex - 2);
}
if (_pages.Count > 3 && _pages.ContainsKey(pageIndex + 2))
{
_pages.Remove(pageIndex + 2);
}
return _pages[pageIndex][pageOffset];
}
}
protected
virtual
void RequestPage(int pageIndex)
{
if (!_pages.ContainsKey(pageIndex))
{
_pages.Add(pageIndex, null);
LoadPage(pageIndex);
}
}
protected
virtual
void LoadPage(int pageIndex)
{
PopulatePage(pageIndex, FetchPage(pageIndex));
}
protected
virtual
void PopulatePage(int pageIndex, IList<T> page)
{
if (_pages.ContainsKey(pageIndex))
_pages[pageIndex] = page;
}
protected
IList<T> FetchPage(int pageIndex)
{ //这里是从数据库里取,列表请求的页码对应的数据
return (IList<T>)LocalData.FetchRange(pageIndex * PageSize, PageSize);
}
LocalDatd.cs
public
static
class
LocalData
{
private
static
Random rnd = new
Random();
private
static
List<Product> listProduct;
static LocalData()
{ //假设这里是存在本地数据库里的聊天记录的信息有1000条
listProduct = new
List<Product>(1000);
for (int i = 0; i < 1000; i++)
{
listProduct.Add(new
Product { Id = i, Name = "聊天记录-" + rnd.Next(1000, 10000).ToString(), Category = "" });
}
}
//分页取库里的聊天记录(模拟)
public
static
IList<Product> FetchRange(int skip, int take)
{
return listProduct.Skip(skip).Take(take).ToList();
}
}
在viewmodel中初始化
private
VirtualizingCollection<Product> vList;
public
VirtualizingCollection<Product> VList
{
get { return vList; }
set { vList = value; }
}
private
static
Random rnd=new
Random ();
public MainPageViewModel()
{
vList = new
VirtualizingCollection<Product>(1000);
}
我们运行,上下滑动,看一下效果s


我们看到内存中加载的页数始终是3-5页。而且滚动条已经显示的是总数为1000时的高度。
这就是所谓的数据虚拟化了。
比起点击加载,滑动加载,以数据虚拟化的方式,内存占用更少。(滑动加载数据源是不断被add的并没有delete)
另一点在用户体验上,滚动条的变化也给了用户预期,列表到底有多少数据。
当然我这里只是演示性的demo。具体应用还有很多需要注意的地方。比如说如果数据来源于网络,从磁盘读取,较慢的时候。
就需要一些异步的的读取处理。在实现索引器的时候我们这里是根据固定的页数移除,还可以根据最近的加载时间判断哪些页面要移除等等。
最后我还要留个小小的问题。public
class
VirtualizingCollection<T>:IList<T>,IList在这里我实现了两个很相近的接口。
谁能告诉我这么做是为啥?请留言回答:) 回答正确的,月薪15k以下的,你们老板对不起你!
最后的呐喊!所有关注/从事Windows Phone平台的道友,能不能在android,ios大行其道,wp沦为小平台的无奈下,
别再敝帚自珍!一起为wp平台多奉献一些自己的经验,多分享一些优质的资源。
能不能在您看完文章的此刻,顺便给这些同在wp平台挣扎的道友,轻轻的,点一下【推荐】!!!
demo下载
Windows phone UI虚拟化和数据虚拟化(二)的更多相关文章
- Windows phone UI虚拟化和数据虚拟化(一)
今天和大家分享一些关于windows phone ui虚拟化和数据虚拟化的一些知识. 也顺便回答我上一篇[LongListSelector 控件 在 wp7 和wp8中的不同之处]里,留下的那个问题, ...
- 基于windows server 2012 的微软桌面虚拟化实战教程
http://abool.blog.51cto.com/8355508/1587489/ Windows Server2012 中的“远程桌面服务”服务器角色中就提供了允许用户连接到虚拟机.Remot ...
- Silverlight 中datagrid控件-- 通过设置数据虚拟化加速显示
定义依赖属性作为datagrid的数据源 protected static readonly DependencyProperty ViewLogsProperty = DependencyPrope ...
- 【原创】Linux虚拟化KVM-Qemu分析(二)之ARMv8虚拟化
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 即兴小探华为开源行业领先大数据虚拟化引擎openLooKeng
@ 目录 概述 定义 背景 特点 架构 关键技术 应用场景 安装 单台部署 集群部署 命令行接口 连接器 MySQL连接器 ClickHouse连接器 概述 定义 openLooKeng 官网地址 h ...
- KVM 介绍(3):I/O 全虚拟化和准虚拟化 [KVM I/O QEMU Full-Virtualizaiton Para-virtualization]
学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...
- Windows 7开发:UAC数据重定向 - Win32 Native
Windows 7开发:UAC数据重定向 - Win32 Native 目标 本动手实验中,您将会学习如何: • 故障排除一个文件重定向 问题 • 使用Process Monitor查找引起问题的根本 ...
- 用 Blend 给Windows Phone 应用创建 示例数据
前言 创建 示例数据(Sample Data) 是提高程序开发效率的一个很有效方法,有了它,我们调UI的时候就不必每次都运行应用,然后在手机上观看页面效果了,配合 “AlignmentGrid.pn ...
- TortoiseGit和msysGit安装及使用笔记(windows下使用上传数据到GitHub)[转]
TortoiseGit和msysGit安装及使用笔记(windows下使用上传数据到GitHub) Git-1.7.11-preview+GitExtensions244SetupComplete+T ...
随机推荐
- spring security 5 There is no PasswordEncoder mapped for the id "null" 错误
转载请注明出处 http://www.cnblogs.com/majianming/p/7923604.html 最近在学习spring security,但是在设置客户端密码时,一直出现了一下错误提 ...
- #82. 【UR #7】水题生成器
链接:http://uoj.ac/problem/82 今天是世界水日,著名的水题资源专家蝈蝈大臣向世界宣布了他的一项新发明 —— 水题生成器. 每道题目都有一个正整数的难度值.水题生成器虽然强大但是 ...
- JQueryUI基础知识学习
JQueryUI官网 http://jqueryui.com/ 菜鸟教程 http://www.runoob.com/jqueryui/jqueryui-tutorial.html
- this/super/static/final/匿名对象/继承/抽象类/访问权限修饰符
1.this关键字的作用 1)调用本类中的属性; 2)调用本类中的构造方法;且只能放首行,且必须留一个构造方法作为出口,即不能递归调用 3)表示当前对象; 2.匿名对象 ...
- setuid
-r-s--x--x #s就是setuid,仅可用在二进制文件,对目录设置无效
- Spring Boot: Spring Starter Project
好久没有创建过新项目,楼主发现Spring Boot项目创建失败了!!! 其中有两处错误: [图一不知道是哪里错,果断删掉重输入一次.成功进入下一步 其余步骤也没有错误,然而 最后一步失败了,如图 ...
- Servlet和JSP之有关Servlet和JSP的梳理(二)
JSP JSP页面本质上是一个Servlet,JSP页面在JSP容器中运行,一个Servlet容器通常也是JSP容器. 当一个JSP页面第一次被请求时,Servlet/JSP容器主要做一下两件事情: ...
- UVA 12563 Jin Ge jin Qu [h] ao 劲歌金曲 (01背包)
每首只能唱一次,而且中间不能不唱歌,所以先把状态赋值为-1,以区别合法状态和非法状态,在唱歌曲目最多的条件下,离开时间应该尽量晚. 状态定义f[i][j]考虑前i首歌唱歌时间为j的最大唱歌曲目 #in ...
- CPP-基础:TCHAR
目 录 定义 使用原理 1.定义 TCHAR是通过define定义的字符串宏[1] 2.使用原理 因为C++支持两种字符串,即常规的ANSI编码(使用""包裹)和Unicode编码 ...
- Django-C002-深入模型,到底有多深
此文章完成度[100%]留着以后忘记的回顾.多写多练多思考,我会努力写出有意思的demo,如果知识点有错误.误导,欢迎大家在评论处写下你的感想或者纠错. ORM介绍:对象关系映射(英语:(Object ...