1、客户端中对DataForm中数据的操作
说到这个一般是指对列表新建和编辑的DataForm中数据的操作,我们知道在编辑和新建DataForm中,只有形如:
<SharePoint:FormField runat="server" id="ff2{$Pos}" ControlMode="New" FieldName="Title" __designer:bind="{ddwrt:DataBind('i',concat('ff2',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Title')}"/>
的FormField类型的SharePoint的WebControl才被最终的数据提交操作识别,并提交,而且,如果在页面上同一个字段有多个FormField Control的话,最终提交的数据是页面自上到下最后一个FormField的值。
所以,我们一般就是利用Javascript来操作FormField在客户端生成的HTML标签,这些标签是有一些规律的,SharePoint Designer的Team Blog里面有一篇文章详细介绍了如何利用Javascript来操作这些字段控件:Using Javascript to Manipulate a List Form Field
如果我们可以操作这些字段控件,对这些字段控件生成的HTML标签值进行赋值修改的话,我们可以隐藏原本生成的控件标签,使用自己的编辑控件,然后,在提交前,把用户编辑的值赋给隐藏的DataForm提交时能识别的字段控件标签,就可以实现比较深入的编辑新建页面的定制了。
其实,在这种状况下,我们相当于只把DataForm作为提交数据的一个载体了。
2、提交数据到服务器端
DataForm中与服务器端的数据交互基本是由“http://schemas.microsoft.com/WebParts/v2/DataView/runtime”这个名称空间下(一般在DataForm的XSLT中以ddwrt出现)ddwrt:GenFireServerEvent(string EventString)方法来实现。其实原理很简单ddwrt:GenFireServerEvent这个方法解析出来以后是__dopostback()方法,会触发Postback,把EventString作为Postback的参数,然后DataForm会根据EventString处理相应的数据提交操作。
比如,如果你在DataForm使用了一个<a href="javascript: {ddwrt:GenFireServerEvent('__commit;__refresh;')}">Submit</a>来向服务器端做一个提交操作,在客户端显示的时候这个串就被解析成了<a href="javascript: __doPostBack('ctl00$m$g_18a01f88_4df1_41ef_abef_151d51648f2c','__commit');">Submit</a>,前部分ctl00$m$g_18a01f88_4df1_41ef_abef_151d51648f2c是DataForm Web Part的ID,后面的就是事件的参数,__doPostBack的方法在每个页面你都可以通过查看源文件看到这个方法,它干的事情就是提交页面。
GenFireServerEvent可以通过__dopostback向服务器提交任何参数,DataForm可以识别的一些特定的参数包括:
1)__commit; 所有的数据提交都要包括这个参数。DataForm会根据当前的模式进行提交操作,如果当前是Listform模式,就会把数据提交到列表中去。如果是Table模式,就确认对DataForm的其他操作。说白了,所有的新建,修改,删除都需要加上这个参数才能生效。
2)__refresh; 刷新页面
3)__cancel; 取消这个参数之前的所有操作,即在这个参数之前的所有参数都不起作用
4)__redirectsource; 把页面转向到URL中的Source参数对应的地址,如果URL中没有Source参数则返回列表的默认视图
5)__redirect={URL}; 把页面转向到一个制定的URL,这个URL中可以是通过XSLT动态赋值,一个列表编辑DataForm页面提交的例子:<a href="javascript: {ddwrt:GenFireServerEvent(concat('__commit;__refresh;__redirect={DispForm.aspx?ID=',@ID))}">Submit</a> 意思就是编辑提交完成以后跳转到项目显示页面。
6)__delete={ID=3}; 删除某个列表项,参数是ID,一般我们可以在显示所有列表的页面给每个项目加一个删除超链接,这个ID的参数就需要在XSLT里面动态附加,形如
<a href="javascript: {ddwrt:GenFireServerEvent(concat('__delete={ID=',@ID,'};__delete={ID=4};__delete={ID=5};__delete={ID=6};__commit;__refresh;'))}">delete</a>
其中concat是用来拼接文本的xslt函数,把@ID与其他的参数拼接。
__delete这个参数在一个GenFireServerEvent中可以存在多个比如:
<a href="javascript: {ddwrt:GenFireServerEvent('__delete={ID=3};__delete={ID=4};__delete={ID=5};__delete={ID=6};__commit;__refresh;')}">delete</a>这个删除链接就是同时删除ID为3,4,5,6的四个列表项。可以看到用了__commit;参数来真正让DataForm去执行删除的动作。
7)__workflowStart={{06D5963E-BE1C-4EC8-9021-3DB29C1E55F0},New,{FCE8E874-EE7D-4475-8F2D-F64CAEB07CE0},Parameters} 这个参数比较特殊,一般用户不会直接去手写这个参数,它是使用“自定义操作”(Custom Actions)后自动生成的。DataForm中的这个自定义操作是巧妙的利用了工作流来满足对数据可能的复杂操作的需求,比如删除项目后,给管理员发邮件提醒等,都可以利用自定义操作来实现。
自定义操作(Custom Actions)的原理也不复杂:每个网站都会有一个叫Custom workflow process的列表,所有自定义操作和其他SharePoint列表的工作流一样都会在Workflows文档库下面创建出来,不同的是所有自定义操作会绑定到Custom workflow process列表上,并允许用户手动启动。__workflowStart中的第一个参数就是网站上Custom workflow process列表的GUID,New是新建一个工作流实例,第三个参数是自定义操作对应的工作流模板的GUID,最后的就是自定义操作里面设置的工作流参数了。
GenFireServerEvent还可以用来Postback任意参数,DataForm中包含一种类型的参数形如:
<ParameterBinding Name="dvt_groupdir" Location="Postback;Connection"/>
这种参数就是从Postback回来的值中取得,做分页的时候需要使用到利用GenFireServerEvent来传值。
3、一些补充
1)既然GenFireServerEvent方法其实就是解析成了__dopostback方法,把DataForm的ID和参数给了__dopostback方法。所以如果我们需要,我们可以修改DataForm的ID,不要使用默认生成的GUID,如果你用了自定制的ID以后,使用备份恢复部署后DataForm的ID就不会变了,这样的话我们直接在javascript里面写__dopostback方法了,因为DataForm的ID我们可以确定的知道了。
这个东西有什么用呢?目前我碰到的唯一一个需要用到这个变态方法的地方是,当需要实现可以让用户选择列表中的某几个列表项进行删除的时候,就必须用到这个方法了。
2)使用了自定义操作以后,我们通过备份网站,恢复网站进行定制的部署后,我们会发现自定义操作都不能用了,点击带有自定义操作的按钮就报错!这个的解决办法我会在下一篇文章中给出解决方法。
3)我们是用Custom List Form以后,“Attach File”这个功能就失效了!如何即可以定制编辑页面,有可以正常使用附件上传功能呢?我会在后来第5篇文章中谈到;
(本文中所有的方法都是定制技术,是不使用任何后端代码下对SharePoint列表数据进行定制操作的方法。
所以,可能有些你感觉用代码开发的时候都不是问题的问题在这里却被当成问题拿出来讨论了。
但是,当你遇到一个完全的定制项目或者你想了解SPD的能力的时候,你会发现这是有价值的)