WPF进阶之接口(4):ICommand实现详解
上一章WPF进阶之接口():INotifyPropertyChanged,ICommand中我们遗留了几个问题,我将在本节中做出解释。在详细解释ICommand实现之前,我们现在关注一下什么是:弱引用(WeakReference) 弱引用: 表示弱引用,即在引用对象的同时仍然允许垃圾回收来回收该对象。 如果应用程序的代码可以访问一个正由该程序使用的对象,垃圾回收器就不能收集该对象,那么,就认为应用程序对该对象具有强引用。 弱引用允许应用程序访问对象,同时也允许垃圾回收器收集相应的对象。如果不存在强引用,则弱引用的有限期只限于收集对象前的一个不确定的时间段。使用弱引用时,应用程序仍可对该对象进行强引用,这样做可防止该对象被收集。但始终存在这样的风险:垃圾回收器在重新建立强引用之前先处理该对象。 弱引用特别适合以下对象:占用大量内存,但通过垃圾回收功能回收以后很容易重新创建。 假设 Windows 窗体应用程序中的一个树视图向用户显示了复杂的选项层次结构。如果基础数据量很大,则用户使用应用程序中的其他部分时,在内存中保留该树会导致效率低下。 当用户切换到应用程序的其他部分时,可使用 WeakReference 类来创建对该树的弱引用,并销毁所有强引用。当用户切换回该树时,应用程序会尝试获得对该树的强引用,如果得到,就不必重新构造该树。 要对某个对象建立弱引用,请使用要跟踪的对象的实例创建一个 WeakReference。然后将 Target 属性设置为该对象,将该对象设置为 null。 可创建短弱引用或长弱引用: 短 垃圾回收功能回收对象后,短弱引用的目标会变为 null。弱引用本身是托管对象,和任何其他托管对象一样需要经过垃圾回收。短弱引用是 WeakReference 的默认构造函数。 长 调用对象的 Finalize 方法后,会保留长弱引用。这样,您就可以重新创建该对象,但该对象仍保持不可预知的状态。要使用长引用,请在 WeakReference 构造函数中指定 true。 如果对象的类型没有 Finalize 方法,则会应用短弱引用功能,该弱引用只在目标被收集之前有效,运行终结器之后可以随时收集目标。 要建立强引用并重新使用该对象,请将 WeakReference 的 Target 属性强制转换为该对象的类型。如果 Target 属性返回 null,则表示对象已被收集;否则,您可继续使用该对象,因为应用程序已重新获得了对它的强引用。 这是摘自MSDN的解释,那么简单来说,弱引用与强引用的区别在于,它允许GC回收。 ICommand实现: 在WPF进阶之接口():INotifyPropertyChanged,ICommand我们看到在ICommand的实现代码中: internal class CommandManagerHelper
{
internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
{
if (handlers != null)
{
// Take a snapshot of the handlers before we call out to them since the handlers
// could cause the array to me modified while we are reading it. EventHandler[] callees = new EventHandler[handlers.Count];
int count = ; for (int i = handlers.Count - ; i >= ; i--)
{
WeakReference reference = handlers[i];
EventHandler handler = reference.Target as EventHandler;
if (handler == null)
{
// Clean up old handlers that have been collected
handlers.RemoveAt(i);
}
else
{
callees[count] = handler;
count++;
}
} // Call the handlers that we snapshotted
for (int i = ; i < count; i++)
{
EventHandler handler = callees[i];
handler(null, EventArgs.Empty);
}
}
} internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested += handler;
}
}
}
} internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested -= handler;
}
}
}
} internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
{
AddWeakReferenceHandler(ref handlers, handler, -);
} internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
{
if (handlers == null)
{
handlers = (defaultListSize > ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
} handlers.Add(new WeakReference(handler));
} internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
{
if (handlers != null)
{
for (int i = handlers.Count - ; i >= ; i--)
{
WeakReference reference = handlers[i];
EventHandler existingHandler = reference.Target as EventHandler;
if ((existingHandler == null) || (existingHandler == handler))
{
// Clean up old handlers that have been collected
// in addition to the handler that is to be removed.
handlers.RemoveAt(i);
}
}
}
}
} CommandManagerHelper类主要是对将事件用WealReference的形式实现,Add和Remove。为什么要这样处理呢,在C#中的弱事件(Weak Events in C#)我们谈到了,虽然C#在实现事件订阅机制的时候是线程安全的,但在用户的使用过程中仍然可能导致事件的handler不能同步,即一个线程可能已经将事件注销了,而另一个线程可能仍然要触发事件,那时系统就会抛出 NullReferenceException而导致系统崩溃。原因请详细阅读C#中的弱事件(Weak Events in C#)一文。 可以看到我们在实现事件的订阅机制的时候,必须要考虑到上述问题。上一章节ICommand实现正是采用了Solution2(弱引用)来解决此问题。即每次添加、删除和触发事件之前,必须检查WeakReference的List,查看是否已经存在,或是已经被GC回收,相应采取处理。 这样与MVVM相关的几个基本的Inerface,我已经陆续向大家介绍完毕。下一节,将向大家详细介绍控件的重写,可能在此过程中仍然要涉及几个接口(IList,IEnuerator,ICollection等),但是这些Interface主要是与控件重写技术相关的,我将放入相应章节中做出解释。
转自:http://hi.baidu.com/leo_han/item/46128d371590ba9db90c030a
WPF进阶之接口(4):ICommand实现详解的更多相关文章
- WPF进阶之接口(1):IValueConverter,IMultiValueConverter
看一个例子,FontFamily="Trebuchet MS, GlobalSansSerif.CompositeFont" .这样一条简单的语句,熟悉WPF的人在xaml中可能经 ...
- Java进阶(三十二) HttpClient使用详解
Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...
- Android进阶笔记:Messenger源码详解
Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...
- 【python3+request】python3+requests接口自动化测试框架实例详解教程
转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...
- OpenCV学习C++接口 Mat像素遍历详解
OpenCV学习C++接口 Mat像素遍历详解
- Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...
- 微信JS接口汇总及使用详解
这篇文章主要介绍了微信JS接口汇总及使用详解,十分的全面.详尽,包含分享到朋友圈,分享给朋友,分享到QQ,拍照或从手机相册中选图,识别音频并返回识别结果,使用微信内置地图查看位置等接口,有需要的小伙伴 ...
- “全栈2019”Java第六十五章:接口与默认方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- python+requests接口自动化测试框架实例详解
python+requests接口自动化测试框架实例详解 转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实 ...
随机推荐
- 【LeetCode】117. Populating Next Right Pointers in Each Node II (2 solutions)
Populating Next Right Pointers in Each Node II Follow up for problem "Populating Next Right Poi ...
- Tomcat中部署Java Web应用程序的方式
Tomcat中部署Java Web应用程序的几种方式: #PetWeb是工程名 1.在TOMCAT_HOME\conf\server.xml文件的HOST节点中加入 <Context docBa ...
- C# 基础: new 和 overrider 的区别
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- cocos2dx 关于lua 绑定的环境配置官方文档翻译与 将自己定义c++方法绑定到lua的的方法
网上有好多写如何讲自己定义的方法绑定到lua的文章,当中都仅仅对环境配置做了简单的介绍,看到有的帖子写在绑定中遇到了各种各样的error.大部分是因为环境配置不对导致的,下面是官方的文档有标准的说明, ...
- cookie是什么? -- web
cookies是由网络server存储在你电脑硬盘上的一个txt类型的小文件,它和你的网络浏览行为有关,所以存储在你电脑上的cookies就好像你的一张身份证,你电脑上的cookies和其它电脑上的c ...
- unity5,UI Button too small on device than in Game View解决办法
假设测试设备为iphone5(横屏).下面说明如何使真机上ui显示效果与Game View中一致. 1,首先Game View左上角屏幕规格选 iPhone 5 Wide (16:9),如图: 2,在 ...
- max_int和-1
#include <stdio.h> int main(int argc, char *argv[]) { unsigned ; ) printf("umax:%u == -1\ ...
- HDOJ 5289 Assignment 单调队列
维护一个递增的和递减的单调队列 Assignment Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Ja ...
- request的生存期只限于服务器跳转
症状: 刚才想做一个实验,在a.jsp中向request添加属性(页面编码为UTF-8),在b.jsp中删除该属性(页面编码为ISO-8859-1),通过ServletRequestAttribute ...
- Handler实例
Handler使用例1这个例子是最简单的介绍handler使用的,是将handler绑定到它所建立的线程中.本次实验完成的功能是:单击Start按钮,程序会开始启动线程,并且线程程序完成后延时1s会继 ...