在上一篇博客中,笔者分享了一些从页面整体的角度对页面与ViewModel的思考。在本文中笔者希望从相对细节的角度分享一些对页面与ViewModel的思考。

比如,当我们在更新View Model中的绑定数据时,应该怎样更新呢?简单的自然可以用新的数据实例直接替代旧的,但是这样容易造成UI界面闪烁。尤其是绑定数据是一个列表的情况下,如果整个列表被替换,可以非常明显的看到列表"一闪"。这样的用户体验无疑是不理想的。那么我们在更新View Model中绑定的数据实例时,可以采用差异更新的方法。以一个数据列表为例,在更新时对比新旧列表,先遍历新表,对每一个元素查看在旧表中有无对应元素。如果没有,说明是新增的数据,可以将该新表中的元素同时加入到一个临时表和旧表中,如果旧表有排序则还需要注意插入的位置。如果有,说明是旧元素更新,则用新元素的值更新旧元素后,将旧元素加入到临时表中。然后遍历旧表,对旧表中每一个元素在临时表中查看有无对应元素。如果有,则不用做任何处理。如果没有,则说明该元素已经被删除,应该在旧表中将这个元素移除。这样对UI界面的更新看起来会比较平滑。

这里写一下笔者在旺信UWP中所写的差异化更新算法,权当抛砖引玉。

            var bList = new List<bool>();//辅助列表
for (int j = ; j < MainList.Count; j++)//辅助列表初始与旧表同长
{
bList.Add(false);
}
for (int i = ; i < groups.Count; i++)//遍历新表
{
bool inserted = false;
bool contains = false;
for (int j = ; j < MainList.Count; j++)//新表中的元素与旧表对比
{
if (groups[i].key != MainList[j].key)//如果不是同一元素
{
if ((groups[i].key == "群主")//尝试插入
|| (
MainList[j].key != "群主" && MainList[j].key != "管理员"
&& (groups[i].key == "管理员" || groups[i].key.CompareTo(MainList[j].key) < )
)
)
{
MainList.Insert(j, groups[i]);
bList.Insert(j, true);
inserted = true;
Debug.WriteLine("inserted:" + j + "," + groups[i].key);
break;
}
}
else//如果是同一元素,用新表元素内容更新旧表
{
contains = true;
MainList[j].update(groups[i]);
bList[j] = true;
break;
}
}
if ((!contains) && (!inserted))//不包括在旧表内,也没有插入,则追加在旧表尾部
{
MainList.Add(groups[i]);
bList.Add(true);
}
}
for (int i = bList.Count; i > ; i--)//对比辅助列表,移除旧表中不应再存在的元素
{
if (!bList[i-])
{
try
{
MainList.RemoveAt(i - );
}
catch (Exception)
{
Debug.WriteLine("RemoveAt error:" + i);
}
}
}

在这段代码中,用新的数据groups更新旧的数据MainList。

再比如,在我们的页面上,我们一般都会放置一个表示正在加载数据的控件。这个加载中控件的状态一般也是绑定一个后台数据的。对于一般的页面,我们可以采取在加载数据前后设置该绑定值的方法来修改页面所显示的加载状态。而对于UWP旺信这种依赖网络,一个页面可能同时调用多个网络接口更新数据的情况,就不是非常合适了。比如a,b两个接口同时请求数据,将加载状态置为加载中。如果a接口先返回,则会将加载状态置为完成。而实际上b接口仍然在请求数据,正确的加载状态应该还是加载中,直到b接口也返回。为此笔者想到了可以增加一个初始值为0的计数变量,当有加载请求时就自增1,当请求异步结束或回调返回时就自减1,绑定的加载状态的get方法根据当计数是否为0返回是否在加载状态。这样一来就可以使多个加载请求都能正确的改变加载状态。

在旺信UWP中,笔者就为ViewModel添加了这样的变量:

        public bool isLoading
{
get { return loadingCount > ; }
} private int _loadingCount = ; public int loadingCount
{
get { return _loadingCount; }
set { _loadingCount = (value < ? : value); RaisePropertyChanged("isLoading"); }
}

在xaml页面上则将ProgressRing控件的IsActive属性绑定到isLoading变量上:

<ProgressRing Grid.Row="2" Grid.RowSpan="2" IsActive="{x:Bind thisData.isLoading,Mode=OneWay}" Width="60" Height="60" Foreground="{ThemeResource WXThemeColorBrush}"></ProgressRing>

在调用异步方法前后,并不直接设置isLoading变量,而是采取上面提到的,调用前loadingCount变量自增1,完成后loadingCount变量自减1的方法来影响ProgressRing控件所显示的加载状态IsActive。

另外,在使用x:Bind方法时,笔者发现如果把绑定image图片控件的source绑定到一个string,当绑定的string值为空时会在log中出现exception。即使在string值为空时把image控件隐藏也仍然会出现。然而旺信中数据的属性值基本都是从服务器传输到客户端的,有时确实会有一些图片的url为空。这样一来最好给图片属性值都给一个默认值。那么默认值该如何确定呢?如果是普通的占位图片,那么可能在不该出现图片的地方显示。经过实践,笔者选择了在应用中加入一个长度为0的图片,把该图片的uri作为图片属性的默认值。当然这个方法只是消除了log中的exception,具体是否提升了应用的效率,还有待验证。

以上就是笔者对对页面与ViewModel的细节的思考,希望能对小伙伴们开发UWP应用有所帮助。当然也欢迎大家拍砖,提出更多更好的经验,让我们共同进步。

页面与ViewModel(下)的更多相关文章

  1. mvvm框架下页面与ViewModel的各种参数传递方式

    传单个参数的话在xaml用     Command={Binding ViewModel的事件处理名称}    CommandParameter={Binding 要传递的控件名称} ViewMode ...

  2. JavaScript 在不刷新或跳转页面的情况下改变当前浏览器地址栏上的网址

    JavaScript 在不刷新或跳转页面的情况下改变当前浏览器地址栏上的网址 var stateObject = {}; var title = "改变后的网址的标题"; var ...

  3. JS 模拟手机页面文件的下拉刷新

    js 模拟手机页面文件的下拉刷新初探 老总说需要这个功能,好吧那就看看相关的东西呗 最后弄出了一个简单的下拉刷新页面的形式,还不算太复杂 查看 demo 要在仿真器下才能看到效果,比如chrome的里 ...

  4. ASP.NET MVC中的cshtml页面中的下拉框的使用

    ASP.NET MVC中的cshtml页面中的下拉框的使用 用上@Html.DropDownList 先记下来..以做备忘...

  5. selenium从入门到应用 - 5,页面对象设计模式下的页面模块

    本系列所有代码 https://github.com/zhangting85/simpleWebtest 本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下 ...

  6. 广告域名审核之后跳转技术:点击域名A页面iframe框架下的链接,域名A跳转到域名B

    广告域名审核之后跳转技术:点击域名A页面iframe框架下的链接,域名A跳转到域名B注:域名B为afish.cnblogs.com 域名A页面代码:<!DOCTYPE html PUBLIC & ...

  7. 页面与ViewModel(上)

    在UWP淘宝与旺信中,笔者主要负责页面与控件的制作,这些工作看似简单,但要想做的全面细致仍然需要深入的思考.本文想分享一些在UWP旺信的制作过程中,笔者在UI页面与控件制作上体会到的一些心得.可能笔者 ...

  8. dragloader.js帮助你在页面原生滚动下实现Pull Request操作

    dragloader.js是一个面向移动Web开发的JavaScript库,帮助开发者在使用页面原生滚动时,模拟上/下拉手势,实现Pull Request操作. 在移动设备上,一般会使用 drag d ...

  9. jsp页面在IE8下文本模式自动为“杂项(Quirks)”导致页面显示错位

    最近在修改网站的响应式的页面时,由于都是套样式页面,修改过程都是粘贴复制,导致了一些细节问题在IE8下暴露出来: 遇到的问题就是在在Chrome,火狐页面都正常,唯独在IE8下页面样式显示乱样了,但是 ...

随机推荐

  1. 谈谈DOMContentLoaded:Javascript中的domReady引入机制

    一.扯淡部分 回想当年,在摆脱写页面时js全靠从各种DEMO中copy出来然后东拼西凑的幽暗岁月之后,毅然决然地打算放弃这种处处“拿来主义”的不正之风,然后开启通往高大上的“前端攻城狮”的飞升之旅.想 ...

  2. 我为NET狂官方面试题-数据库篇答案

    题目:http://www.cnblogs.com/dunitian/p/6028838.html 汇总:http://www.cnblogs.com/dunitian/p/5977425.html ...

  3. 在Ubuntu 16.10 安装 git 并上传代码至 git.oschina.net

    1. 注册一个账号和创建项目 先在git.oschina.net上注册一个账号和新建一个project ,如project name 是"myTest". 2.安装git sudo ...

  4. DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)

    上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...

  5. History API与浏览器历史堆栈管理

    移动端开发在某些场景中有着特殊需求,如为了提高用户体验和加快响应速度,常常在部分工程采用SPA架构.传统的单页应用基于url的hash值进行路由,这种实现不存在兼容性问题,但是缺点也有--针对不支持o ...

  6. Python(九)Tornado web 框架

    一.简介 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过 ...

  7. 微信小程序前端源码逻辑和工作流

    看完微信小程序的前端代码真的让我热血沸腾啊,代码逻辑和设计一目了然,没有多余的东西,真的是大道至简. 废话不多说,直接分析前端代码.个人观点,难免有疏漏,仅供参考. 文件基本结构: 先看入口app.j ...

  8. 【夯实PHP基础】PHP常用类和函数总结

    本文地址 代码提纲: 1. 字符串处理类及函数 2. 数组处理类及函数 3 .web处理类及函数 将常用的PHP的类和函数总结到这里,主要是 自己用过的,比较有感觉. 1. [字符串处理] 1)[ut ...

  9. Flex 布局教程:语法篇

    作者: 阮一峰 网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便 ...

  10. Android之ContentProvider数据存储

    一.ContentProvider保存数据介绍 一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数 ...