RSS

Tag Archives: SharePoint

解决服务器上Office客户端无法在线操作文档

因为讲课的需要,经常要做各种各样的演示。

在SharePoint 2010使用默认设置全都安装在一台Windows Server 2008 R2的机器上之后,发现没办法直接用Word把文档存进文档库,也不能从文档库里面在线创建文档。

后来发现,估计是服务器端IE之类的有什么诡异安全性限制,如果想要在线打开、创建、编辑、保存文档库中的文档的话,需要在客户端里进行如下设置(以Word为例,其实都一样的):

打开那个BackStage菜单(也就是全屏的那个菜单),点击选项,点击“信任中心”,点击“信任中心设置”,选择“受保护的视图”,把所有钩都去掉:

image

这样之后,就可以在线对文档进行操作了。不过发现在服务器上直接在线打开、新建编辑文档的速度超慢无比,只要是通过WEBDAV访问的都慢到爆……一直忍了很久,直到今天忍无可忍,上网一搜,发现居然是这个东西搞的鬼:

image

嗯……这个就是IE的代理设置页面,只要把“自动监测设置”这个东西关掉,WEBDAV的速度就恢复正常了,无语。

 

Posted by on 2010 年 12 月 02 日 in SharePoint

Leave a comment

Tags: ,

在SharePoint 2007中呈现一个干净的Main区域

在几乎所有SharePoint网站的母版页中,经常都包含了顶部Logo、顶部导航、左侧导航、页面边框等等内容,当然最主题的部分还是ID为“PlaceHolderMain”的一个ContentPlaceHolder,所有的页面主要内容都呈现在这个容器中。

在有些情况下,我们经常会需要去掉那些周围的内容,而在页面中只呈现这个主要区域的内容,一些典型的应用场景包括:在类似对话框的弹出窗口中,把页面嵌入到一个iframe中,等等。

在SharePoint 2010里面,我们可以很简单地在页面的Url地址之后加上一个“IsDlg=1”,SharePoint自己就会去掉那些周围的元素,只显示PlaceHolderMain这个容器和相应的Ribbon区域。实际上,在2010的那些对话框窗口中,都是使用了这种机制来实现的。

如果您还在使用SharePoint 2007,又想要在某些场景中实现类似的效果,我们可以完全仿照2010的机制来在2007中实现这样的功能。

在SharePoint 2010的母版页中,所有需要在对话框中隐藏的区域,都有一个class:“s4-notdlg”,当页面Url中设置了“IsDlg=1”这个查询参数之后,就会由脚本将这个class的display属性设置为“none”,从而将这些内容隐藏掉。

到这里,我们就知道在2007里面应该如何实现这个功能了:

第一步,打开冰箱门

使用SharePoint Designer编辑我们的母版页(不管是默认母版页还是您自定义的母版页),把在这种状态下需要隐藏的容器的元素标签(div、table、tr、td等等)都加上一个我们自定义的class(假设叫做“Erucy-notdlg”)。我数了一下,在2007的默认母版页default.master中,如果需要把周围元素都隐藏干净,只需要在8个元素中增加这个标签;在默认的layouts下的applicatioin.master(绝大多数layouts下页面的母版页)中,同样只需要8个。(在本文末会给出我修改好的这两个文件供大家参考)

第二步,把大象装进去

接下来,我们就需要在IsDlg=1或者的情况下,来设置“Erucy-notdlg”这个class的display属性,我们可以通过js来实现这一点。这里面,我们使用一种标准的SharePoint做法:创建一个feature,加入一个ControlId为“AdditionalPageHead”的用户控件,将一部分代码加入到页面的head标签中(AdditionalPageHead是SharePoint所有母版页中都有的一个DelegateControl控件,在head区域中,允许我们通过feature的方式将自定义的一些css引用、js脚本等内容灵活地添加到head标签中,很多开发人员在编辑母版页的时候都会把这个看似无用的控件去掉,实际上,这是非常不可取的做法)。

首先,我们来编写这个需要的css文件,非常简单:

   1: .Erucy-notdlg{
   2:   display:none;
   3: }

然后,编写一个Feature,先是feature.xml:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <Feature Id="FEC9EB94-004C-4E02-AE5D-32D350C6CD5B"
   3:     Title="开启干净的Main区域"
   4:     Version="1.0.0.0"
   5:     Scope="Site"
   6:     xmlns="http://schemas.microsoft.com/sharepoint/">
   7:   <ElementManifests>
   8:     <ElementManifest Location="Controls.xml" />
   9:   </ElementManifests>
  10: </Feature>

然后是Feature的主体文件,Controls.xml,来加入一个用户控件:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
   3:   <Control Id="AdditionalPageHead" 
   4:       ControlSrc="~/_controltemplates/ClearMain.ascx" />
   5: </Elements>

最后,就是编写这个最重要的ascx。在这个ascx中,我们会判断,如果页面Url中包含了IsDlg=1、或者页面在一个iframe中,那么就输入上面的那个css文件引用:

   1: <%@ Control Language="C#" ClassName="ReferenceControl" %>
   2: <script type="text/javascript">
   3: if (window.location.search.indexOf('IsDlg=1') > 0 ||
   4:   (window.parent != null && window.parent != window)) {
   5:     document.writeln('<link rel="stylesheet" type="text/css" href="/_layouts/Erucy/dlgframe.css"/>');
   6: }
   7: </script>

第三步,关上冰箱门

把这些feature文件、css文件、ascx文件都做成一个wsp包(如果你不知道怎么做的话,可以去搜搜……SDK里面也有讲),然后部署之,进到网站集管理里面激活feature,搞定!

这个时候,如果我们需要在弹出窗口中隐藏掉周围内容,只需要在弹出窗口的Url中加上IsDlg=1;如果是放到页面中的iframe里面(比如自带的“网页查看器”Web部件),默认就会去掉所有周围内容:

image

修改后的default.master和application.master下载:点我点我!

 

Posted by on 2010 年 11 月 20 日 in SharePoint

Leave a comment

Tags: , ,

在SharePoint 2010的Web部件页中恢复左侧导航

在SharePoint默认的几种Web部件页中,均是不包含左侧导航的(或者叫快速启动栏),原因在于这些Web部件页的模板都重新定义了母版页中左侧导航区域的ContentPlaceHolder,将里面的内容设置为空白。

在SharePoint 2007的时候,恢复Web部件页的左侧导航很容易,直接用Designer编辑页面,将页面中PlaceHolderLeftNavBar的Content控件删掉即可,使用母版页中默认定义的内容。

但是到了SharePoint 2010中,这样一个步骤还不够。由于在2010中母版页完全采用div+css的布局,因此在Web部件页中还有额外的内容来隐藏掉左侧导航,将下面这部分内容也一并删掉即可:

   1: <SharePoint:UIVersionedContent ID="WebPartPageHideQLStyles" UIVersion="4" runat="server">
   2:     <ContentTemplate>
   3: <style type="text/css">
   4: body #s4-leftpanel {
   5:     display:none;
   6: }
   7: .s4-ca {
   8:     margin-left:0px;
   9: }
  10: </style>
  11:     </ContentTemplate>
  12: </SharePoint:UIVersionedContent>

当然,如果需要恢复所有Web部件页的左侧导航,可以直接修改Web部件页的模板,位置在:C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\2052\STS\DOCTEMP\SMARTPGS

 

Posted by on 2010 年 09 月 22 日 in 未分类

Leave a comment

Tags:

按条件决定SharePoint 2010日历颜色

SharePoint 2010中对列表的日历视图有了极大的改进,之前曾经简单写过一篇blog进行了一些简单介绍。新的日历视图的渲染方式与之前完全不同,采用了AJAX后台加载、JavaScript渲染的机制,极大的提高了日历的显示效率(在SharePoint 2007的时候日历渲染是非常非常慢的)。不过也正是因为所有的日历都是使用AJAX加载、然后用JavaScript进行显示的,这也导致了对日历样式的控制变得更加复杂。

最近某个客户有这样一个需求:希望能够在日历视图中,根据不同情况将条目显示为不同的颜色,经过一番研究之后,找到了如下解决方案(不需要编写后台代码,仅通过十几行js代码就可以)。

第一个问题,如果分辨应该使用什么颜色?这个颜色条件可以采用日历列表中“地点”字段来进行判断,比如写成“因私外出”显示成红色、写成“因公外出”显示成蓝色、写成“办公室”显示成绿色,客户同意通过制度来限制此字段的填写(在实际场景中,日历是通过个人的Outlook填写,并同步到SharePoint上的)。

第二个问题,如何将“地点”这个字段显示出来,并且作为能够判断颜色的依据?这方面,可以借助日历视图设置中的“副标题”进行控制。在周视图和日视图中,都可以设置一个字段为“副标题”,显示在标题的下方,在页面中就可以通过js代码来得到这个副标题。那你可能会有一个疑问:在月视图中怎么办?实际上,如果设置了副标题的话,不论是月视图、周视图还是日视图,在显示日历条目的那个div元素上,都会包含一个title属性,格式为:“开始时间 – 结束时间  标题(副标题)”。因此,我们只需要把“地点”字段设置成周视图和日视图的副标题即可(月视图采用周视图的副标题字段作为title属性)。

最后一个问题,如何动态来控制颜色。刚刚曾经提到过,在2010的日历视图中,日历条目都是通过AJAX进行加载的,我研究了一下SharePoint日历渲染的那个js文件(好几百KB),发现没有开放出加载完成的事件接口(这个文件估计是用C#代码转换出来的,比较难读)。因此,我们就只能通过最土的方法:不断轮询页面日历中的条目div,找到之后,再根据div的title属性来判断应该显示为哪种颜色,日历条目的div有一个专门的class:ms-acal-item,通过jquery,我们可以很容易使用class名称来找到这些条目。

综上,实现的方式为:在有日历的页面中添加一个内容编辑器,里面写上如下的js代码:

   1: <script src="/_layouts/jslib/jquery.js" type="text/javascript"></script>
   2: <script type="text/javascript">
   3: var _calColorMap = {"ok":"#ff0000"};
   4: function _calColor(){
   5:   $('div.ms-acal-item').each(function(){
   6:     var title = $(this).attr('title');
   7:     if(typeof(title) != 'undefined' && title != null){
   8:       if(title.lastIndexOf(')') == (title.length - 1)){
   9:         title = title.substring(title.lastIndexOf('(') + 1, title.length -1);
  10:         if(typeof(_calColorMap[title]) != 'undefined'){
  11:           $(this).css('background-color', _calColorMap[title]);
  12:         }
  13:       }
  14:     }
  15:   });
  16:   setTimeout('_calColor()');
  17: }
  18: ExecuteOrDelayUntilScriptLoaded(_calColor, "SP.UI.ApplicationPages.Calendar.js");
  19: </script>

稍微对这段代码进行一些解释:

第1行,引用jquery的脚本文件。我这个demo里面只是一个演示,更好的做法是把js的引用通过feature的方式加入到母版页的head标签里面;当然,引用的位置也可以放到文档库里,或者如果企业策略允许服务器访问外网的话,可以直接从jquery网站里面去进行引用。

第3行,这里面设置了一个字典变量,来进行“地点”-“颜色”的映射,这个demo里将“ok”地点显示成红色(#ff0000),当然,这个映射关系完全也可以通过后台的一些配置列表来实现,以js的形式输出到页面中就可以。

中间的部分就是判断div的title属性,找到对应的“地点”,并设置div的颜色。

第16行,将这个方法每隔50毫秒就执行一次。因为2010的日历视图在切换显示时间、显示方式的时候是没有后台代码提交的,页面不会刷新,全都是js操作,所以有必要随时进行页面元素的遍历(不用担心浏览器执行效率,我测试过,50毫秒的间隔对浏览器的CPU占用没有丝毫影响)。

第18行,这个是SharePoint 2010中的方法,意思是在页面加载完“SP.UI.ApplicationPages.Calendar.js”这个js文件之后,再执行_calColor这个方法(SharePoint 2010中很多js文件都是动态加载的)。

下图是这段代码在一个日历视图上的执行效果(月视图,test那个是全天事件,所以没有显示时间):

image

这个是使用“地点”字段进行颜色的判断,各位看官稍加发挥一下就可以根据自己的需要进行颜色的设置了。

在SharePoint 2007中使用后台代码进行自定义日历显示的时候(使用SPCalendarView控件),是可以设置每个日历项的颜色的,不过这段代码到了2010中似乎会有一些问题,一些老外已经有了blog去描述这个问题(大致解决方法就是将日历视图的显示回复成v3的模式,这个控件有一个属性可以控制是v3模式显示还是v4模式),篇幅所限就不在此赘述了,有需要的看官可以直接去google一下。

 

Posted by on 2010 年 09 月 20 日 in 未分类

Leave a comment

Tags:

关于“超出管理员强制要求的列表阈值”

今天早晨接到迪美的电话,说BPIOU网站出问题了,有用户发了一封邮件给他们说是在“我的课程”中查看不到课程(这个用的是SharePoint默认的列表视图),并且课程预订的时候显示失败(这个用的是JavaScript对象模型),报错界面如下:

clip_image002

clip_image002[5]

进去看了一下,发现用户课程预订列表的项目已经超过了5000,达到了SharePoint默认设置的列表阈值限制。

OK,上面是一个真是的故事,故事讲到这里先暂停一下,看一下这个所谓的“列表阈值限制”究竟是个什么东东。

我们知道,在SharePoint 2007的时代,SharePoint被客户抱怨最多的问题大体归纳起来有三:(1)列表性能;(2)权限分配过于繁琐;(3)工作流。

其中第一个问题极大的限制了SharePoint的应用场景,很多用户都看过那篇著名的白皮书(链接我就不给了),也听过很多我们讲的课程,都会对两个数字有非常深刻的印象:2000和20000——这是在白皮书中的两个建议数值:一个视图/文件夹中的条目不要超过2000,一个列表中的条目不要超过20000。当然,这只是一个建议,KB同学这篇BLOG(点我点我)中对这个数字进行了一个具体的说明。今天我们主要不是想讨论这两个数字,而是谈一下在SharePoint 2010中对列表性能问题的改进。

首先,按照微软的官方说法,在SharePoint 2010中,一个列表中可以支持到千万数量级的条目(你没看错,是千万数量级,和之前有了质的飞跃),不过前提条件是要做好列表容量规划。在2010的管理中心 – Web应用程序管理 – 资源限制 页面中,我们看到2010中新增的对于列表的一些阈值限制,其中最重要的第一个限制,就是列表视图阈值,默认设置为5000个(见下图)。

image

在SharePoint的在线帮助文档中对5000这个数字的来历有一个解释(这同时也解释了为什么在2007里面如果一个列表内容多了会造成性能的极大影响),摘录如下:为了最大程度地减少数据库争用,SQL Server 经常使用行级锁定策略来确保在不对访问其他行的其他用户产生负面影响的情况下准确地进行更新。但是,如果某个读取或写入的数据库操作(如查询)导致一次锁定 5,000 个以上的行,则让 SQL Server 暂时将锁定升级至整个表,直至数据库操作完成,会更加有效。请注意,实际数目并非始终为 5,000,该数目可能会因您的网站、数据库中的活动量以及网站配置而异。如果执行此锁定升级,其他用户将无法访问该表。如果此锁定升级经常发生,则所有用户都会遇到系统性能下降的情况。因此,若要帮助最大程度地降低资源密集型数据库操作的影响并平衡所有用户的需要,阈值和限制是必不可少的。

因此在2010中,SharePoint一旦发现用户在查询视图的时候,查询结果有可能超过5000,就会出现故事一开头的那两个错误。这个设置能够阻止一些可能会对服务器整体性能造成影响的用户操作,免得因为个别用户的操作影响到其他用户的正常使用。

介绍到这里,我们再来关心一下如何解决这个问题。回到故事的场景中:课程预订的列表条目终于超过了5000,但其实每个用户自己并不需要查看所有的课程预订记录(管理员除外),只关心自己预订的课程就够了。因此,在“我的课程”视图和课程预订的时候,都是先按照“创建者”进行了一层筛选,仅显示出当前用户所创建的课程预订记录。

那么为了解决上面的问题,只需要对“创建者”这个字段创建一个索引就好了(进入到列表设置页面,管理索引,加入“创建者”)。

当SharePoint判断到当前视图的第一个筛选条件(注意:只是第一个)设置过索引的时候,这个5000阈值数的限制,就不是针对整个列表的条目了,而是针对在这个索引字段下,所查询出的结果条目数。一个用户可能预订超过5000节课程嘛?当然不可能,一共都没这么多课。因此,在修改了这一设置之后,系统就可以一往如前的运行了,只是在课程预订的时候,要稍稍慢一点点,让SharePoint有时间去维护自己的索引。

故事在这里就告一段落了,不过事情并没有结束。

在管理中心的“资源限制”界面中,还有一些相关设置和这个阈值数目是有关的,这些设置主要针对如下的一些场景:

场景一:我是管理员,我需要有特权。

不错,管理员在系统中确实会有一些有别于普通用户的操作,比如查看所有用户预订的课程,这个时候如果还按照5000阈值数目进行限制,就显得太不合情理了。SharePoint针对管理员单独提出了另外一个阈值,这个值默认是20000(一个熟悉的数字),只要在管理员的视图中,经过索引栏过滤之后,结果总数不超过20000,管理员就可以正常工作了。

场景二:我是后台程序,我需要一些特别操作。

对于人来讲,总数20000基本上已经足够看的了,而对于一些机器运行的程序而言,20000这个数量还远远不够班。例如,我们需要每天晚上针对所有用户预订的课程进行一次统计分析,这种可怕的数据量查询可能并不会对一般的用户造成影响(除了那些熬夜打游戏,偶尔上一下网站的夜猫子),因此,SharePoint专门可以设置一个时间段,在这个时间段内,用户的查询不采用任何的阈值限制,可以随意运行程序或操作。

上面只是SharePoint 2010对列表条目性能带来的改进中的一个方面,由于篇幅所限,本文没有涵盖所有的针对容量规划的设置(比如2010中新增加的元数据导航,就是一个可以用于规划管理超大型数据量的一种方式),这些规划和设置可以在technet网站中找到,也可以在SharePoint在线帮助中查看到(看到第一个出错界面中有一个链接么?点进去就是在线帮助内容了)。

 

Posted by on 2010 年 08 月 09 日 in 未分类

Leave a comment

Tags:

SharePoint 2010中日历列表的一些改进

又是写书的过程中发现的。SharePoint 2010在日历列表一些比较细节的地方有了不少很不错的改进:

1、在新建一个事件的时候,如果修改了开始时间,那么结束时间会跟着顺延。另外,默认情况下结束时间不再和开始时间一样,而是比开始时间晚一个小时。比如一开始是从8点到9点,如果我们把开始时间改成10点,那么结束时间会自动变成11点。当然这个做的有点傻,比如开始时间是8点,我把结束时间改成5点,之后把开始时间该成10点,那么结束时间会自动变成7点……算法真是一目了然。

2、终于可以直接在日历视图的某一天或者某个时间段上,直接点击添加来在指定时间添加事件了。只需要把鼠标指到这个日期或者时间的空白处,就会浮现一个添加链接,英文版叫“Add”,繁体中文版好像叫“增添”,简体中文版叫“为第二阶段删除的项目添加” @_@,没错,你不是在做梦:

cal2

这一版的翻译可见一斑,希望在RC能改掉(RC已经出了,我还没装)

3、可以在一个视图上显示多个日历的内容了:

cal1

其中绿色和黄色的部分来自两个不同的日历列表,通过下面这个界面进行设置:

cal3

从下面这个界面中我们可以看到,除了支持SharePoint列表之外,还可以显示Exchange中的日历:

cal4

另一个翻译让我比较吐血,这个“解决”在英文版里叫“Resolve”……

还好这些翻译问题改起来也不麻烦,改一些resx文件就好了。在C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\config\Resources\wss.zh-CN.resx

 

Posted by on 2010 年 02 月 11 日 in 未分类

Leave a comment

Tags:

CollaDec 之前的三个SharePoint工具开源发布

之前ColldaDec有三个工具,后来网站当掉之后就没有办法下载了,其实一直都想整理一下开源掉,正好有人问下载地址,借此机会发布出来。

当时所有的工具、文档(包括陈曦录的几个视频)和源代码都发布到CodePlex上了:

1、WPManager(Web部件管理器):用于在SharePoint 2007上部署、卸载Web部件,无需编写dwp/webpart描述文件,无需编写manifest,无需手动修改web.config,只需要打开生成的dll文件,选择部署位置,点击“部署”就可以一切搞定。支持dll、cab和wsp三种部署方式。同时支持部分Web部件的卸载功能,同时还有个彩蛋。

发布地址:http://wpmanager.codeplex.com

2、OSSEventManager(事件处理程序管理器):可以方便的在一个列表上部署、挂载、卸载SharePoint 2007的列表条目事件处理程序。

发布地址:http://osseventmanager.codeplex.com

3、Friendly Query:使用类似T-SQL语句的形式进行SharePoint列表查询,无需任何CAML。之前写过一篇blog:点击这里

发布地址:http://fquery.codeplex.com/

 

 

Posted by on 2010 年 01 月 09 日 in 未分类

Leave a comment

Tags:

页面库无法捕获到Added事件?

标题党一下。

问题发生在一个文档库(文档模板是“空白页”)中,写了一个Added的事件处理程序,把标题字段改成文件名(不带扩展名的),但是发现新建页面的时候(不是上载)没效果。难道没有捕获到Added事件?

经过单点调试,发现事件是捕获到了,因为里面抛出一个异常导致没有正常执行。

很奇怪的问题:在Added事件中,properties.ListItem居然是null!(ListItemID是0),一般而言只有在Adding的时候才是null(因为Adding时条目还没有真正被创建出来),不知道是不是SharePoint的bug,不知道是不是在某些hotfix更新过了(我对hotfix的跟踪不是很及时。。。),也不知道在其他文档模板的情况下有没有问题。

解决方法是这样的:

   1: using(SPWeb web = properties.OpenWeb())
   2: {
   3:   SPFile file = web.GetFile(properties.AfterUrl);
   4:   SPListItem item = file.Item;
   5:   // do something with the item
   6: }

可以看到,AfterUrl是可以拿到这个新页面的地址的,而且可以正常拿到文件和条目,说明在Added的这个时候条目已经出现了,但是为什么直接用properties.ListItem拿不到呢?有时间的话可以去挖掘一下……

 

Posted by on 2009 年 02 月 17 日 in 未分类

Leave a comment

Tags:

SharePoint JavaScript Lib – SPJsLib发布

之前在某个不能使用任何后台代码的项目中开始研究的用javascript去控制SharePoint,略有心得,也曾经在赏梅斋的moss开发群里做过一次和这个话题相关的讲座,记录点击这里

前一阵整理了一下这个项目里用到的一些javascript的方法,并随着后面的几个项目添加了一些新的内容进去,现在发布出来。

地址是:http://www.codeplex.com/SPJsLib

主要是基于jQuery这个javascript库来做的,我做的时候和测试的时候jQuery还是1.2.6版本,现在已经是1.3.1了,在项目的release里也包含了一个1.2.6版本经过压缩的jQuery文件。

使用的时候不需要对jQuery有了解,当然如果了解jQuery的话更快速的实现更丰富的功能。

具体的使用方法参考项目网站里的文档(word 2003格式,中文的,几乎每个方法都有sample code,代码里的注释都是英文的),这里大概介绍一下这个库的作用:

这个JavaScript库大致分成两大部分:

第一部分:访问SharePoint内容

通过AJAX技术(jQuery提供了很方便的跨浏览器的AJAX解决方案),调用SharePoint内置的Web Services,读取、查询、添加、修改或删除列表中的条目。此外还支持了对当前用户的用户配置文件中各个属性的读取(这是某个项目的产物)

比如,下面这段简短的代码可以更新myList列表中所有lookup字段查阅了ID为19的条目的标题(来自文档):

   1: var res = queryItems('myList', "<Where><FieldRef Name='lookup' LookupId='TRUE'/><Value Type='Lookup'>19</Value></Where>", ['ID']); 
   2: var ids = []; 
   3: $.each(res.items, function(idx, item){ 
   4:     ids.push(item['ID']);        // $.each是jquery中的方法,效果类似于C#中的foreach 
   5: }); 
   6: var updateRes = updateItems('myList', ids, {'Title':'These are items lookup 19!'}); 
   7: alert(updateRes.success);

 

第二部分:控制SharePoint表单

这个表单指的是列表的新建和编辑表单,支持的字段类型包括:

单行文本、多行文本(纯文本和带格式的文本)、数字(普通和百分比)、货币、选项(下拉列表、Radio、多选)、查阅项(单选、多选)、时间和日期(仅日期和带时间)、是/否、人员和组(不完全支持)、超链接、图片

提供的功能包括:

1、隐藏/只读字段

2、获取/设置字段的值

3、级联两个选项(下拉列表)类型的字段

4、级联两个查阅项类型的字段

5、为查阅项和选项(下拉列表)提供筛选功能(如果比较多的话选起来会方便很多)

6、从客户端检测字段是否为空(和字段的那个设置无关,甚至可以根据某个字段的设置来决定是否要检查某些字段,文档中有个例子)

7、重定义“确定”和“取消”按钮的行为

这两部分内容结合起来,不用任何C#代码也能够完成很多操作了。当然,最好对javascript有一定的了解(不需要对jQuery有了解,当然了解更好)。

文档中的两张图(查阅项字段的级联和筛选):

clip_image002

clip_image002[9]

只读部分字段的效果:

image

如果有任何问题或者建议的话可以在blog上或者codeplex上反馈给我,欢迎试用(已经在IE6/IE7/FF3.0上经过了初步测试)~

 

Posted by on 2009 年 02 月 03 日 in 未分类

Leave a comment

Tags:

SDP工作流循环初探(下)

之前我们分析了为什么一个简单且看似合理的SPD工作流循环为什么有可能在执行过程中跳出循环的原因,我们的目的在于让这个工作流变得更加稳定。

当一个工作流无法正常工作的时候,可能就会需要其他工作流的帮助。一个人干不了的活,大家一起干。我们需要有另外一个工作流实例,来对第一个工作流进行“监督和提醒”。另外一个工作流即可以放在同一个列表上(因为它们是不同的模板,可以同时产生两个不同的实例),或者另一个辅助列表上。放在同一个列表上在列表设计上比较简单,但是因为同时有两个不同的工作流实例在运行,分析和工作流设计要格外小心;放在多个列表上的话,每个列表上只运行一个实例,通过一个字段关联起来,逻辑上更容易分析,但一旦涉及到迁移和部署就会非常麻烦(见老赵的这篇文章)。为了做测试,我先把所有工作都堆在一个列表上。

思路是这样的,工作流两个模板分成工人和监工两个角色,工人负责干活(执行具体的操作),监工负责提醒工人。工人执行完操作之后,告诉监工“我干完了!”,然后监工说“哦?那么你可以先休息一下”并且在到点之后提醒工人说“嘿!该干活了!”。实际上,这是两个工作流实例互相触发的过程,并通过一个标志位决定目前是工作者应该执行操作,还是监视者执行操作。当然,为了避免之前所说的“触发在退出之前发生”的情况出现,两边都要有一个确认时间段,等待另外一方结束后自己才开始运行。

这两个工作流的设计如下:

首先是工人:

image

然后是监工:

image

其中的Mark就是标记为,决定哪个工作流应该运行,初始值设置成true。执行过程是这个样子的:一开始两边都触发,但因为Mark为true,所以工人开始,监工退出 –> 工人先休息5分钟(偷懒一下) –> 设置标记,触发监工运行 –> 干活后退出 –> 监工被触发后(以为这个实例的触发是由Mark = false引起的,所以监工必然继续运行)先休息5分钟(等工人把活干完并且工人实例退出) –> 设置标记,触发工人实例 –> 工人被触发(同理,它是被Mark = true引起的,所以必然继续运行) –> 休息5分钟(这5分钟的目的就在这里体现出来了,它是在等待监工实例的退出,否则如果监工因为尚未退出没有被工人的后续操作触发,而且工人自己的实例也出现触发早于退出的情况出现时,那么就没有人提醒工人继续工作了) –> ……于是可怜的工人就在监工的控制之下不断地开始计数了。

我们以工人实例的5分钟休息和监工实例的5分钟休息作为代价,换来了两者互相触发的稳定流程。所以这一方法理论上的计数间隔时间是10分钟,据我测试实际时间平均在15分钟左右。

可以高枕无忧了吧任其运行了吧,还不能!为什么呢?在实际的应用中,除了这两者互相触发之外,还可能由用户去修改这个条目,从而唤醒那个已经停止了的实例。让我们来分析一下可能出现的局面:工人正在睡觉(等待监工退出),此时监工已经做完了本职工作退出 –> 就在工人睁开眼睛,准备提醒监工(设置标志位)之前,某个外来用户做了个更新,当头一棒叫醒了监工(因为工人正在运行,所以没有新的工人实例出现) –> 监工懒洋洋地睁开眼睛,发现现在还不应该工作(标志位尚未被工人更新),于是打算退出 –> 而就在监工从醒来发现没有活干到退出的这一段过程中,工人完成了本职工作(设置标记位、计数) –> 这样一来,由于在工人干活的时候监工还没有退出所以新的监工实例没有出现,如果工人干完活退出前就发生了自我提醒的事情(自我触发发生在退出之前),也不会有新的工人实例出现!于是,两个人因为外来者的干扰同时结束了工作,没有人负责计数了!

好吧……我承认这种情况非常极端,我在测试过程中同时开了个Console每隔1-60秒随机更新一下条目作为外部干扰,在流程跑了一整个晚上之后仍然在正常运行(已经计数了31次),但是从理论上来讲,上面的这种情况是仍有可能出现的(如果实例退出时间 > 工人所有的实际操作时间)。为了避免这种情况的出现,我们需要在两个工作流中再次加入等待流程,等待又用户外部干扰产生的意外唤醒退出后再向下执行。

我没有具体做实验,但是设计了这样一种编排方式:

image

在工人中,将Mark标记设置放在暂停之前,以便提前触发监工;监工等待1天让工人干完事情,然后设置标记触发工人,等待5分钟后再做一个HeartBeat(随便更新一个字段)。监工的5分钟和工人的2小时都是为了避免另一方因为外部操作而被唤醒。我们可以讲用户外部操作这个动作插入上述流程中的每个操作之间,来分析外部操作究竟是否会影响到整个计数流程的进行。因为情况比较多,我就不在这里一一分析了。需要保证的是,监工的第二次暂停必须远小于工人的暂停(因为触发是不规律的,要留一个比较大的浮动范围),同时工人的暂停也要远小于监工的第一次暂停。这个流程理论上的计数间隔是1天零5分钟。

文章在这里得到了一个相当复杂,但几乎cover了所有情况的一个解决方案(我说几乎是以为我在做设计时脑袋都大了,不知道是不是漏过了什么信息)。如果各位看官有更好的解决方案,也欢迎在后面留言。

ps. 这个玩意儿在我这边的实际项目背景是这样的:有一个列表,每个条目都有一个RAG(Red, Amber & Green)状态字段,根据不同情况的不同Date Due,在Date Due内RAG状态为绿色;再过一个月之内,RAG变成黄色;超过一个月后RAG变成红色。可以说这是比较常见的一个应用,但之所以采用SPD工作流的方式进行循环触发的原因,首先是客户不允许编写后台代码(否则timerjob轻松搞定这个需求);其次,SharePoint的计算字段中不能采用Today公式,换句话说SharePoint的计算字段不是在取值时计算,而是在条目更新时计算的(所以就算像某

 

Posted by on 2008 年 11 月 23 日 in 未分类

Leave a comment

Tags: