上一章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实现详解的更多相关文章

  1. WPF进阶之接口(1):IValueConverter,IMultiValueConverter

    看一个例子,FontFamily="Trebuchet MS, GlobalSansSerif.CompositeFont" .这样一条简单的语句,熟悉WPF的人在xaml中可能经 ...

  2. Java进阶(三十二) HttpClient使用详解

    Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...

  3. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

  4. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

  5. OpenCV学习C++接口 Mat像素遍历详解

    OpenCV学习C++接口 Mat像素遍历详解

  6. Scala进阶之路-Scala函数篇详解

    Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...

  7. 微信JS接口汇总及使用详解

    这篇文章主要介绍了微信JS接口汇总及使用详解,十分的全面.详尽,包含分享到朋友圈,分享给朋友,分享到QQ,拍照或从手机相册中选图,识别音频并返回识别结果,使用微信内置地图查看位置等接口,有需要的小伙伴 ...

  8. “全栈2019”Java第六十五章:接口与默认方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. python+requests接口自动化测试框架实例详解

    python+requests接口自动化测试框架实例详解   转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实 ...

随机推荐

  1. js特效,轻松实现内容的无缝平滑滚动

    <!DOCTYPE   html   PUBLIC   "-//W3C//DTD   XHTML   1.0   Transitional//EN"   "http ...

  2. Linux命令-目录处理命令:pwd

    pwd 显示当前目录的绝对路径

  3. 摘:C++ 枚举类型

    C++ 中的枚举类型继承于 C 语言.就像其他从 C 语言继承过来的很多特性一样,C++ 枚举也有缺点,这其中最显著的莫过于作用域问题——在枚举类型中定义的常量,属于定义枚举的作用域,而不属于这个枚举 ...

  4. C# ManualResetEvent

    文章转载自:C# ManualResetEvent ManualResetEvent被用于在两个或多个线程间进行线程信号发送. 多个线程可以通过调用ManualResetEvent对象的WaitOne ...

  5. unity, 鼠标与场景交点

    在鼠标与场景交点上放一个mark,并于1s后消失: 新建一个空GameObject,命名为moushHitTest,添加下面脚本: using UnityEngine;using System.Col ...

  6. unity, 查看资源文件类型

  7. ui-router(三)controller与template

    这篇就是在以前的基础上,把客户端angular.js 负责的部分整体串起来演示一下. 我们按照angular执行顺序来做前提准备: (1)Client 根目录下 index.html 首先加载angu ...

  8. CXAnimation.h动画类

    /**************************************************************************** 使用一个CCAnimation对象可以CCS ...

  9. MySQL编码问题集合

    1.以root用户的身份登录,查看编码设置 mysql> SHOW VARIABLES LIKE 'character%'; +--------------------------+------ ...

  10. FreeRTOS 中断优先级配置(重要)

    以下转载自安富莱电子: http://forum.armfly.com/forum.php NVIC 的全称是 Nested vectored interrupt controller,即嵌套向量中断 ...