什么是 『动态数据集合』 ?简而言之,就是当集合添加、删除项目或者重置时,能提供一种通知机制,告诉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的更多相关文章

  1. Unity应用架构设计(6)——设计动态数据集合ObservableList

    什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...

  2. Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)

    『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...

  3. Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)

    在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...

  4. Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期

    > 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...

  5. Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)

    MVVM回顾 经过上一篇文章的介绍,相信你对 MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在.View只关心怎样渲染,而ViewModel只 ...

  6. Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)

    初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...

  7. Unity 3D Framework Designing(7)——IoC工厂理念先行

    一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...

  8. Unity 3D Framework Designing(9)——构建统一的 Repository

    谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...

  9. Unity 3D Framework Designing(5)——ViewModel之间如何共享数据

    对于客户端应用程序而言,单页应用程序(Single Page Application)是最常见的表现形式.有经验的开发人员往往会把一个View分解多个SubView.那么,如何在多个SubView之间 ...

随机推荐

  1. 谨慎能捕千秋蝉(二)——CSRF

    CSRF(Cross Site Request Forgery)跨站点请求伪造. CSRF的本质是当重要操作的参数都能被攻击者预测到,才能成功伪造请求. 一.场景演示 下图是一个伪造请求的场景,按顺序 ...

  2. java多线程四种实现模板

    假设一个项目拥有三块独立代码块,需要执行,什么时候用多线程? 这些代码块某些时候需要同时运行,彼此独立,那么需要用到多线程操作更快... 这里把模板放在这里,需要用的时候寻找合适的来选用. 总体分为两 ...

  3. [Hadoop] - SSH免密码登录

    在安装hadoop之前需要进行ssh免密码登录,ssh 无密码登录要使用公钥与私钥.linux下可以用用ssh-keygen生成公钥/私钥对,下面我以Redhat为例. 我这里只采用一台机器A(10. ...

  4. hive取数时如果遇到这种报错

    如果你hive取数时遇到这种报错:ParseException line 1:78 cannot recognize input near '<EOF>' '<EOF>' '& ...

  5. EFcore与动态模型(二)

    上篇文章中介绍了如何使用ef进行动态类型的管理,比如我们定义了ShopDbContext并且注册了动态模型信息,下面的代码实现了动态信息的增加: Type modelType = IRuntimeMo ...

  6. iOS回顾笔记( 02 ) -- 由九宫格布局引发的一系列“惨案”

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  7. 【转载】JavaScript继承详解(二)

    这一章我们将会重点介绍JavaScript中几个重要的属性(this.constructor.prototype), 这些属性对于我们理解如何实现JavaScript中的类和继承起着至关重要的作用. ...

  8. 中软卓越IT培训:给IT程序员的18个忠告

    1 .想清楚,写清楚,说清楚,才是真正的清楚! 2 .多花点时间沟通清楚需求,才能把握正确方向! 3 .修复需求错误的成本是代码错误的几十倍! 4 .程序员最大的坏习惯就是:急于动手写代码! 5 .提 ...

  9. 移动端利用rem实现自适应布局

    好久没有写博客了,刚好说说最近遇到的移动端布局问题吧. 本来一直是觉得我的页面布局能力还是不错的,当然,是相对于较基础的来说还是不错的.不过,自己写的案例终归是跟实际开发有区别的,自己写案例的是觉得这 ...

  10. AtomicInteger源码分析——基于CAS的乐观锁实

    1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...