It has been about 1.5 years since I last posted. When the market crashed I became fascinated by world of trading (and software) and applied a bit of WPF knowledge to some research and software for another blog. I have 20+ topics still pending for this blog, so there is plenty to write about in 2010 and beyond.
I have been using the MVVM pattern since the beginning of 2008. Since that time there have been plenty of complaints about INotifyPropertyChanged and how developers do not like using strings, etc. Last year several bloggers presented type-safe alternatives that used either reflection or lambda expressions. I really like the elegance and simplicity of the lambda expression, but many are quick to point out the poor performance (same for reflection). Unfortunately ‘poor performance’ says little about usefulness of an implementation. The performance needs to be quantified and compared against all implementations so that ‘poor’ can be put in perspective. Speed is not the only issue, as memory should be compared as well.
This article assumes the reader knows how to use INotifyPropertyChanged and DependencyObjects. (Note: the rest of this article will refer to the string implementation as INotifyPropertyChanged or just INotify). The lambda implementation that is used for the tests is as follows:
INotifyPropertyChanged with Lambda
public static class MvvmExtensions
{
public static void Raise(this PropertyChangedEventHandler handler, object sender, Expression<Func<object>> expression)
{
if (handler != null)
{
if (expression.NodeType != ExpressionType.Lambda)
{
throw new ArgumentException(“Value must be a lamda expression”, “expression”);
}
var body = expression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(“‘x’ should be a member expression”);
}
string propertyName = body.Member.Name;
handler(sender, new PropertyChangedEventArgs(propertyName));
}
}
}
public class DummyLambdaViewModel : INotifyPropertyChanged
{
private string _dummyProperty;
public string DummyProperty
{
get
{
return this._dummyProperty;
}
set
{
this._dummyProperty = value;
OnPropertyChanged(() => this.DummyProperty);
}
}
protected virtual void OnPropertyChanged(Expression<Func<object>> expression)
{
this.PropertyChanged.Raise(this, expression);
}
public event PropertyChangedEventHandler PropertyChanged;
}
Since many developers like to use a base view model class, if the property changed method is put in the base class then children will easily get the support for the lambda expression:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public ViewModelBase()
{
}
protected virtual void OnPropertyChanged(Expression<Func<object>> expression)
{
this.PropertyChanged.Raise(this, expression);
}
public event PropertyChangedEventHandler PropertyChanged;
}
The derived class is now a bit more clean.
public class DummyLambdaViewModel : ViewModelBase
{
private string _dummyProperty;
public string DummyProperty
{
get
{
return this._dummyProperty;
}
set
{
this._dummyProperty = value;
OnPropertyChanged(() => this.DummyProperty);
}
}
}
References
The lambda expression code was taken from the following blogs
http://www.jphamilton.net/post/MVVM-with-Type-Safe-INotifyPropertyChanged.aspx
http://blog.decarufel.net/2009/07/how-to-use-inotifypropertychanged-type_22.html
http://consultingblogs.emc.com/merrickchaffer/archive/2010/01/22/a-simple-implementation-of-inotifypropertychanged.aspx
Testing without WPF Bindings
There are essentially two components to lambda property change notification that cost performance. The first is the creation of the expression (such as () => this.DummyProperty). The second is the actual WPF binding infrastructure that affects all of the property change notification implementations. String property change events have virtually no ‘expression creation’ processing time since it is just a hard coded string (such as “DummyProperty”). By raising property change events when no bindings are attached (and thus no listener to the viewmodel’s PropertyChanged event), we can compare the ‘expression creation’ performance costs of the various property change implementations.
The lambda expressions are roughly 20 times slower than both string INotify and DependencyObjects when the WPF binding infrastructure is not included, giving us a measure of the raw performance cost of just raising the property change event. So far the performance cost of lambda expressions is living up to the ‘poor performance’ label.
Testing with WPF Bindings
Since the prior test is only part of the total processing required for property change notification, it is important to test again with a WPF binding in place so that the WPF binding system can work its magic against the property change events. By having a XAML element (such as a TextBlock) bind its Text property to a property of a viewmodel, WPF’s binding system will now be listening for the property change events and doing its own reflection and internal property management.
Once the WPF binding system is included in the performance tests, the lambda expression implementation drops from 20 times slower to only around 3 times slower. Even though using lambda expressions is slower than the alternatives, testing with the WPF binding system shows the performance hit is probably not as big as many have perceived it to be. Using property change notification on a DependencyObject is the fastest technique since it was designed for that purpose, allowing the WPF binding system to listen to property change events with virtually no overhead and no reflection. However, like the INotify implementation, it uses a string for the property name identification.
Memory Usage
Performance is only half the story. In order to make proper design decisions, it is important to also know the memory characteristics of the various property change techniques. By using a profiler we can measure the number of objects created and destroyed, as well as bytes used during each property change request. The WPF binding system is included in the measurements.
The lambda expressions use almost 7 times the memory as INotify for each property change event, while the DependencyObject property change notification uses no memory at all (but the class itself uses memory). The following screenshot from the profiler shows the WPF binding system objects that are created and destroyed during the INotify event (1,000,000 events):
These are the objects and memory used for the lambda expression (1,000,000 events)
General Guidelines
With this performance and memory usage information we can summarize some loose guidelines for when to use each property change mechanism. Since the DispatcherObject is a WPF class, it has its own set of memory requirements to support
- DispatcherObject: Use if speed critical and frequent property change events occur
- INotifyPropertyChanged: Use if large numbers of viewmodels are created (it is more lightweight than DependencyObject), but speed is also important
- Lambda Expressions: Use for type-safe property change notification when speed is not critical.
Test Application
You can download the application and code used for these tests here. The code is junk code, and is not a demonstration of proper design, testing, or MVVM principles.
Disclaimer
These tests were performed using a viewmodel with only one property. Performance can differ on viewmodels with many properties. Tests were also performed by raising the property change notifications in a loop. Real world performance can vary due to locality of reference.
相关推荐
本资源"reprint-0.3.0.tar.gz"就是从PyPI官网获取的一个Python库——`reprint`的特定版本,版本号为0.3.0。 `reprint`库主要解决的是在Python程序中动态更新控制台输出的问题。在开发过程中,我们有时需要实时显示...
Gartner在2018年发布的研究笔记中,特别提到了应用安全测试(AST)市场的现状和发展趋势。研究笔记的标题为“应用安全测试市场的魔法象限”,它由分析师Ayal Tirosh、Dionisio Zumerle和Mark Horvath撰写,涉及...
A simple, unified fingerprint authentication library for Android with RxJava extensions. Eliminates the need to deal with the different available Fingerprint APIs, including Imprint and Samsung Pass....
reprint 是一个适用于 Python 2/3 的简易变量绑定与多行输出刷新的库
Processing of signals is often facilitated by transforming to a representation in which individual components are statistically independent. In such a natural coordinate system, the components of the ...
reprint 使用说明 直接从datasource,dbgrid,stringgrid导入数据, 只需简单设置,不用手工制作,即可生成您需要的报表,具有预览功能。即可自定义纸张,又可适应 打印机默认纸张。各种打印设置,功能更强大。 ...
reprint是一个Python 2/3模块,用于绑定变量并刷新终端中的多行输出。 用于计算Unicode字符宽度的解决方案来自 特征 Python 2/3支持 简单的变量绑定和变量更改后自动刷新命令行 同时多行刷新,每行绑定到不同的...
reprint 使用说明 本人长期使用delphi做数据库的开发,报表控件使用Quickrpt,在打印上经常遇到一些问题,于是自己经常编写一部分打印的程序,经过总结开发了这个控件。 本控件可打印 datasource,dbgrid,...
不推荐使用请改用 ,它支持... 在您的Application.onCreate ,使用Reprint.initialize(this)初始化Reprint。 这将加载棉花糖模块和Spass模块(如果包含)。 然后,在代码中的任何位置,都可以调用Reprint.authenticate
标题中的“Gartner Reprint_APM_英文原版”指的是由知名市场研究机构Gartner发布的关于应用性能监控的报告原文版。Gartner是一家全球领先的信息技术和市场研究公司,其报告对业界具有广泛的影响力。 描述中提到的...
reprint 使用说明 本控件可打印 datasource,dbgrid,stringgrid. 一 、控件属性: 1、colstitle 设置报表的列标题属性 (1) Print:boolean;;是否打印 (2) Font:tfont;;字体 (3) Rowsline:tpen;;横线...
Free-Reprint-Articles.com - **平台特点**:允许再版的文章,可以提高文章的传播范围。 - **应用**:适合希望增加文章曝光率的作者。 #### 18. Favouritearticles.com - **平台特点**:可能侧重于精选优质文章。 ...
在安卓平台上,指纹识别技术为用户提供了安全便捷的身份验证方式,极大地增强了应用的安全性和用户体验。本文将深入探讨如何在Android应用程序中实现指纹识别功能,基于提供的"安卓指纹识别模块",我们将详细介绍...
具有带通选择性的ICA算法可以改善对于带通时间序列的分离以及对于周期性脑功能响应信号的提取. 因此本文提出的方案可将被估计信号, 如:周期性响应信号以及具有平滑空间分布的脑功能激活区, 的先验特性以特征选择的...
是检测估计和调制理论的经典著作,最新版,2013版,英文原版,Highly readable paperback reprint of one of the great time-tested classics in the field of signal processing Together with the reprint of Part ...
重印 描述 按照字母顺序,由Aidan Guarniere,Cassandra Hurlbut,Jonathan Wilferd和翁飞凤撰写。 不可替代令牌(NFT)可以是数字文件,例如图片,动画,音频或视频,但它们不可互换,因为它们是由区块链技术制成的...
根据给定文件的部分内容,可以看出该文档主要涉及的是Gartner公司在2019年发布的十大安全项目的介绍。虽然文档中的具体内容并不多,但是我们可以通过标题、描述以及提供的上下文信息来推测并总结出其中的关键知识点...
Reprint of the sixth (1980) edition》,Classics in Mathematics, Springer-Verlag, Berlin, 1995 - 张恭庆,林源渠编著:《泛函分析讲义》上册,北京大学出版社,1990 - 郑维行,王声望:《实变函数与泛函分析...