EventHandler常用业务分析(1)
EventHandler给我们在MOSS中开发带来了很大的自由度,很方便地就捕获到在数据操作时的事件,插入相应的业务代码,实现我们的业务逻辑。在使用了好长一段时间EventHandler后,忽然想归纳一下我这段时间在使用EventHandler时遇到的问题,给大家分享一下!
1. 在ItemAdding事件或ItemUpdating事件中获取用户输入的值
这是一个很普通的操作,通常我们都会遇到这样一个业务逻辑:只有当用户输入的值符合要求才允许用户添加记录,否则取消该操作;或者在用户添加一条记录时,获取用户输入的值,再去进行其它操作。遇到这些业务,必须的是要在ItemAdding事件中获取到用户用户的值,那我们自然就会很想到一个属性properties.ListItem,这是正在添加的记录项,但恰恰这是添加前的事件,properties.ListItem的值为Null,并不能获取得到,就算在ItemUpdating事件中,properties.ListItem虽然是有值,但并不是用户输入的最新的值,而是原来的值(旧值)。
想在记录项添加时或修改时得到新的值,我们可以直接使用下面的语句
properties.AfterProperties["Title"].ToString();
2. 在ItemAdding事件或ItemUpdating事件中修改该记录项的值
我们有时候在设计列表的时候,会添加一些对用户隐藏的栏,用于记录与该记录相关的信息,只能通过程序去改写此栏的值,那我们在添加新记录项或修改记录项时怎样修改该栏的值呢?
很自然,我们会写出下面的程序
public override void ItemUpdating(SPItemEventProperties properties)
{
SPListItem item = properties.ListItem;
item["Title"] = "这是我指定的值";
item.Update();
}
但很抱歉,运行这段的下场只有一个——出错!系统会报出“保存冲突”的错误信息。回头仔细看看代码,代码在记录项正在修改时,再次修改了该记录项。与SQL相似,MOSS也会在进入ItemUpdating事件前,把该记录项上了锁,以防止该记录项在没完成本次修改前给再次修改,因此这样写注定是失败的!如果是在ItemAdding事件更是如此,在前文说了,在ItemAdding事件时,properties.ListItem的值为Null,该记录项都还没生成,所以根本不可能也不应该通过properties.ListItem来修改某个栏上的值,因为properties.ListItem所表示的是一个记录项旧的值(新增前的旧值没是没有,null){
SPListItem item = properties.ListItem;
item["Title"] = "这是我指定的值";
item.Update();
}
那通过什么属性来修改呢?MOSS一定会提供一个途径给我们做这事的!我们再来关注一下properties.AfterProperties这个属性,从字面意思可以很容易知道,这是记录项新的值,但很可惜,这个属性是只读的,我们也不能直接修改这个属性达到我们的目的。接着往下看,在properties.AfterProperties中还有一个属性ChangedProperties,连起来看,properties.AfterProperties.ChangedProperties字面意思很像是该属性保存该字段改变了的值(SDK也是这样说的,Gets properties that have changed in the collection),这很容易就理解成MOSS会自动比较用户修改了记录的哪些值,开始的时候,我也是这样理解的,但很奇怪,无论我怎样修改记录的值,在调试时,该属性值的Count属性始终是0,并不如我开始所想的!
那时在网上查了很多资料,都只是说奇怪MS为什么会提供ChangedProperties这样一个HashTable类型的属性,而且始终是没有值放到里面去的。在一次反编译MS的官方站点模板中的EventHandler事件程序时,我才恍然大悟!我们应该这样理解ChangedProperties这个HashTable,它是用于给我们修改栏值的一个集合,我觉得SDK的英文应该改成“Gets properties that will be changed in the collection”才对(个人见解),因为在ItemAdding事件或ItemUpdating事件中,记录项并没有真的生成或修改,ListItem代表的是原来的值,AfterProperties代表的是这个记录项将要变成的值,共中的ChangedProperties提供再次修改的一次机会。所以,要在ItemAdding事件或ItemUpdating事件中修改该记录项的值得在这样写
public override void ItemAdding(SPItemEventProperties properties)
{
// Demo1: 在新建时取用户输入的值并作修改
string newValue = "新的值是:" + properties.AfterProperties["Title"].ToString();
properties.AfterProperties.ChangedProperties.Add("Title", newValue);
}
仅仅是需要一行代码就可以修改一个栏的值,并不需要其它的额外代码便可实现我们的目标!{
// Demo1: 在新建时取用户输入的值并作修改
string newValue = "新的值是:" + properties.AfterProperties["Title"].ToString();
properties.AfterProperties.ChangedProperties.Add("Title", newValue);
}
今天先说到这,下一篇会说说在事件中update本身是否会引发update事件的再次触发的问题以及探讨一下事件回滚的实现。