Unity 3D Framework Designing(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加、删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面。有经验的程序员脑海里迸出的第一个词就是 ObservableCollection。没错,它在WPF中盛行其道,通过它开发者可以很方便的达到动态更新界面。要在Unity 3D中使用ObservableCollection还是有些许困难的,因为Mono并不提供ObservableCollection类。但实际上,自己动手去构建一个『动态数据集合』也非难事,核心在于怎样去传播通知。这也是本篇博客的主题。
实现自定义的ObservableList
既然核心在于构建通知机制,谈到『通知』两字,最常见的形式就是以委托或者事件形式将消息广播给监听者。遗憾的是,.NET中常见的集合数据结构List并不支持事件的通知。所以我在自定义的ObservableList中增加OnAdd,OnRemove,OnInsert事件,当集合添加或者删除项时,能广播通知给客户端UI界面。
以下图为例,当点击+时,『以数据驱动界面的形式』,动态的去更新UI界面:

既然要以数据来驱动界面,首先我们需要定义能存放数据的集合,它就是ObservableList,并且是实现了IList 接口:
public class ObservableList<T>:IList<T>
{
//...省略部分代码...
private List<T> _value=new List<T>();
public delegate void AddHandler(T instance);
public AddHandler OnAdd;
public delegate void InsertHandler(int index,T instance);
public InsertHandler OnInsert;
public delegate void RemoveHandler(T instance);
public RemoveHandler OnRemove;
public void Add(T item)
{
_value.Add(item);
if (OnAdd != null)
{
OnAdd(item);
}
}
public bool Remove(T item)
{
if (_value.Remove(item))
{
if (OnRemove != null)
{
OnRemove(item);
}
return true;
}
return false;
}
public void Insert(int index, T item)
{
_value.Insert(index,item);
if (OnInsert!=null)
{
OnInsert(index, item);
}
}
}
可以看到,自定义的ObservableList实现了 IList 接口,并以泛型的形式约束了数据项类型。当添加或者删除项时,提供了以事件的形式告诉客户端UI界面 ,作为观察者的UI可以顺势做出相应的更新。
岔开话题说一下,为什么要用泛型,这是几天前有同学在群里问的?
- 好处1:可以约束数据项的类型,让我们不用每时每刻去强转。比如你往ArrayList中添加了若干数据,因为ArrayList的数据项Item是万能的object,所以你每次取出来都需要将object转为你想要的对象,麻烦。
- 好处2:减少运行时错误,因为是数据项是object,所以在编译时你可以将其强转为任何类型,但万一这个object实际是Datetime类型,但你强转为int,编译时是没问题的,但一运行就报错,泛型约束能有效减少这种情况
完善ObservableList
到目前为止,我们自定义的动态数据集合ObservableList是非常好的设计,但唯一不足的事,它不能支持初始化时通知UI界面更新。 『初始化』 这词可能有点太术语了,我翻译一下就是一般初始化一个List,我们都是像如下方式进行:
public ObservableList<FaceBox> DataSource = new ObservableList<FaceBox>
{
new FaceBox
{
Name = "Eyes",
Level = 10,
Face = "Avatar201_Face",
Badge = new Badge {Icon = "Icon_WeaponRod", ElementColor = "1CB9FFFF"}
},
new FaceBox
{
Name = "Jack",
Level = 8,
Face = "Avatar202_Face",
Badge = new Badge {Icon = "Icon_WeaponSpear", ElementColor = "FF5821FF"}
}
};
显然这即没有触发OnAdd,也没有触发OnRemove等事件,那么初始化或者重置列表时,UI界面还是得不到更新。那我们怎么去解决呢?还记得第一章中BindableProperty吗?对了,解决方案就是它,对列表的初始化或者重置就是对Value进行改变。而BindableProperty内部提供了对Value值改变的监听,一旦Value改变了,将消息广播出去。
OK,我们增强一下ObservableList:
public class ObservableList<T>:IList<T>
{
//省略部分代码...
public delegate void ValueChangedHandler(List<T> oldValue, List<T> newValue);
public ValueChangedHandler OnValueChanged;
//预先初始化,内置的List,防止空异常
private List<T> _value=new List<T>();
public List<T> Value
{
get { return _value; }
set
{
if (!Equals(_value, value))
{
var old = _value;
_value = value;
ValueChanged(old, _value);
}
}
}
private void ValueChanged(List<T> oldValue, List<T> newValue)
{
if (OnValueChanged != null)
{
OnValueChanged(oldValue, newValue);
}
}
}
所以客户端UI界面只要对ObservableList的OnValueChanged事件进行监听,当初始化或者重置时,你也可以得到更新,演示效果如下:

小结
自定义的动态数据集合ObservableList看起来小巧,但五脏俱全,能提供通知机制,可以动态的去更新UI界面。 所有的一切都以数据的改变来驱动UI,这是非常重要的转变。所以看似代码复杂了,但实际上你只要关心数据即可。
源代码托管在Github上,点击此了解
Unity 3D Framework Designing(6)——设计动态数据集合ObservableList的更多相关文章
- Unity应用架构设计(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...
- Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
> 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)
MVVM回顾 经过上一篇文章的介绍,相信你对 MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在.View只关心怎样渲染,而ViewModel只 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
- Unity 3D Framework Designing(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity 3D Framework Designing(5)——ViewModel之间如何共享数据
对于客户端应用程序而言,单页应用程序(Single Page Application)是最常见的表现形式.有经验的开发人员往往会把一个View分解多个SubView.那么,如何在多个SubView之间 ...
随机推荐
- 谨慎能捕千秋蝉(二)——CSRF
CSRF(Cross Site Request Forgery)跨站点请求伪造. CSRF的本质是当重要操作的参数都能被攻击者预测到,才能成功伪造请求. 一.场景演示 下图是一个伪造请求的场景,按顺序 ...
- java多线程四种实现模板
假设一个项目拥有三块独立代码块,需要执行,什么时候用多线程? 这些代码块某些时候需要同时运行,彼此独立,那么需要用到多线程操作更快... 这里把模板放在这里,需要用的时候寻找合适的来选用. 总体分为两 ...
- [Hadoop] - SSH免密码登录
在安装hadoop之前需要进行ssh免密码登录,ssh 无密码登录要使用公钥与私钥.linux下可以用用ssh-keygen生成公钥/私钥对,下面我以Redhat为例. 我这里只采用一台机器A(10. ...
- hive取数时如果遇到这种报错
如果你hive取数时遇到这种报错:ParseException line 1:78 cannot recognize input near '<EOF>' '<EOF>' '& ...
- EFcore与动态模型(二)
上篇文章中介绍了如何使用ef进行动态类型的管理,比如我们定义了ShopDbContext并且注册了动态模型信息,下面的代码实现了动态信息的增加: Type modelType = IRuntimeMo ...
- iOS回顾笔记( 02 ) -- 由九宫格布局引发的一系列“惨案”
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- 【转载】JavaScript继承详解(二)
这一章我们将会重点介绍JavaScript中几个重要的属性(this.constructor.prototype), 这些属性对于我们理解如何实现JavaScript中的类和继承起着至关重要的作用. ...
- 中软卓越IT培训:给IT程序员的18个忠告
1 .想清楚,写清楚,说清楚,才是真正的清楚! 2 .多花点时间沟通清楚需求,才能把握正确方向! 3 .修复需求错误的成本是代码错误的几十倍! 4 .程序员最大的坏习惯就是:急于动手写代码! 5 .提 ...
- 移动端利用rem实现自适应布局
好久没有写博客了,刚好说说最近遇到的移动端布局问题吧. 本来一直是觉得我的页面布局能力还是不错的,当然,是相对于较基础的来说还是不错的.不过,自己写的案例终归是跟实际开发有区别的,自己写案例的是觉得这 ...
- AtomicInteger源码分析——基于CAS的乐观锁实
1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...