• Infopath+Designer工作流设计之四委托代理开发


    委托代理开发

    实现思路如下:

     

    • 在任务列表操作下添加一个设置委托代理的菜单,用户通过该菜单进入委托设置页的表单
    • 开发一个委托设置页,并部署到layouts目录下,该页面用户委托的设置、修改及删除
    • 创建一个列表库,存储用户的委托信息
    • 给任务列表添加一个字段,叫代理者,如果当前任务的分配者有委托设置,则该字段为受委托者的帐号信息,否则为空
    • 创建一个EventHandler并关联到任务列表,当有任务过来时,自动检查对于分配对象是否有委托设置,如果有,则将被委托人填到代理者一栏,如果没有则跳过。

    WSPBuilder介绍

    WSPBuilder的特点是根据文件夹结构来生成WSP文件,这是我个人觉得WSPBuilder最好的特性,也是最有用的功能。 现在,CodePlex上WSPBuilder提供了Visual Studio Addin的安装项目,该Extensions也可以在Visual Studio 2008上使用,该Extensions使得WSPBuilder更好的融合到Visual Studio的开发操作中,安装完"WSPBuilder Extensions 1.03 - Visual Studio Addin (0.9.8.0830)"后,你打开Visual Studio可以有如下WSPBuilder项目:

    在创建好的WSPBuilder项目后,右键点击项目可以看到以下WSPBuilder菜单:

    以上菜单中,值得注意的是以下两个:

    • Build WSP: 创建WSP文件,仅仅是创建而已,不会帮你部署!有很多时候我们其实只需要WSP文件(使用VSeWSS的人应该很希望VSeWSS也能这样)
    • Attach to IIS Worker Processes: 不用在点好几步,然后查找w3wp.exe进程,然后附加了,只要点一下即可开始调试!

    开发的各种SharePoint部件(事件处理、Web Part、模板等)怎么方便的组合起来集成部署(知道用WSP,但是总是没有找到比较好的实施的方法);

    做Solution Package的最主要的问题在于:

     

    • 如何正确的使用Solution Schema里的Element来部署不同的开发产出;
    • 编写正确的manifest.xml文件,打包成WSP文件

    WSPBuilder的好处就在于,你需要做的就是把开发出来的东西放对文件夹!其他一切交给WSPBuilder,使用WSPBuilder自己的模板创建出来的项目,WSPBuilder会自动生成正相应的文件夹结构

    所以,我的做法是使用WSPBuilder项目加上Visual Studio的Post-Event来满足要求:

     

    • 专门创建一个WSPBuilder Project,作为维护创建WSP文件的文件夹结构的项目(也就是说专门用来生成WSP文件的项目);
    • 为不同的功能模块(某个Web Part、事件处理程序等)创建不同的项目,这样方便进行代码管理,工作分配,多人协作,创建的项目加入到第一步创建的解决方案中;
    • 然后接着就是在WSPBuilder Project项目中,创建文件夹,直到每个功能模块对应的项目都能在该项目中找到相应的文件夹;对于每个功能模块对应的项目则在Post-Built中 加入命令行脚本,使在编译通过以后,把编译的结果拷贝到第一步创建的项目的文件夹目录下。

    举个例子,你创建一个WSPBuilder的项目作为维护生成WSP文件的项目:

    创建一个Web Part项目(用的是VSeWSS的Web Part模板),加入到解决方案中

    在WSPBuilder项目中,添加一个叫DemoWebPartFeature的Blank Feature:

    解决方案变成:

    我会把自动生成的elements.xml文件删除,然后修改feature.xml文件:

    把ElementManifests节改成以下样子:

    然后在WSPBuilder项目中创建出80\bin目录,这时候解决方案样子如下:

    然后,对DemoWebPart项目做一些设置,首先把WebPart1.webpart和WebPart1.xml文件的属性改成"Copy Always",这样在该项目的Debug目录中会出现这两个文件:

    接下来,就是在Post-built中添加Copy命令行,把生成的文件拷贝到WSPBuilder项目对应的文件夹下:

     

    copy "$(TargetDir)DemoWebPart.dll" "$(SolutionDir)WSPBuilder\80\bin\";

    copy "$(TargetDir)WebPart1\WebPart1.xml" "$(SolutionDir)WSPBuilder\12\Template\Features\DemoWebPartFeature";

    copy "$(TargetDir)WebPart1\WebPart1.webpart" "$(SolutionDir)WSPBuilder\12\Template\Features\DemoWebPartFeature";

     

    这样,整个项目的初始创建和设置就完成了,把项目迁入到代码管理服务器中,以后就不需要再改动这些设置了。

     

    当你编译DemoWebPart项目的时候,WSPBuilder项目的文件夹下就会是如下样子:

    在WSPBuilder项目的文件夹里面就已经有了所有DemoWebPart相关的文件了,然后我们可以在WSPBuilder项目中创建WSP文件(Deploy和Upgrade菜单在第一次点击Build WSP后才会变成可用)

    所有在WSPBuilder解决方案中的项目右键点击都会出现以上菜单,可以方便的点击"Attach to IIS Worker Processes"来调试。

     

    这样的话

     

    > 开发人员的工作过程就是:从代码管理服务器上获取解决方案的最新版本,然后迁出自己开发的项目,直接选择Deploy Solution,WSP会生成并自动部署到他的环境中,然后在代码中设置断点,点击"Attach to IIS Worker Processes"即可进行调试。

     

    > 集成人员的工作过程:从代码管理服务器上获取最新的项目版本,然后Build WSP,把WSP部署到开发集成服务器上。这个过程,大家可以想象,使用自动build部署的方案完全是可以完成的。

     

    委托数据列表库

    创建一个保存委托数据的列表库,有两种方法可以创建,一种方法是我们直接到网站下面添加一个列表库,然后设置列表库的字段,但该方法显示在迁移时还要手工去完这些额外的事,对于部署上就比较麻烦了,第二种是将创建的操作用Feature完成,并一起封装到部署方案中,部署时只要运行部署方案就可以了。这里我们采用第二种方案实现该功能。

     

    用Feature创建一个列表库一共有以下几步:

     

    创建一个网站列集合,并将这些网站列添加到网站集中

    创建一种内容类型,内容类型中包含了对先前创建的列的引用

    创建ListTemplate,该模板中包含了对内容类型中的引用

    通过ListTemplate创建ListInstance。

    由于网站列的Feature范围均属于网站集范围,无法在网站范围内创建,因此这里要创建两个Feature来实现以上的功能。

     

    MySiteContentTypes:实现将网站列、及自定义内容类型添加到网站集中

     

    WorkFlowDelegate:实现创建ListTemplate、ListInstance等

     

    创建MySiteContentTypes

    在WSPBuilder的解决方案,中点击Add NewItem,选择WSPBuilder下的Blank Feature

    创建完成后,添加两个xml文件,Fields.xml和ContentTypes.xml

    其中必需注意的是ContentType 的ID属性。对于ContentType而言,是有继承关系的,它的继承关系不是通过属性等指定的,而是通过ID进行指定的,其实现方式是parent ContentType ID+self ID,在SDK中明确规定了两种命名方式:

     

    Parent content type ID + two hexadecimal values (the two hexadecimal values cannot be "00"),父ID+两个16进制的数字,并且不可以为00

    Parent content type ID + "00" + hexadecimal GUID,父ID+一个Guid。

    这里采用了第二种方式,内容类型的ID为:0x00B74D936CCD9648AA8DA7E81DE6819675,表示直接生成了一种新的内容类型。Sharepoint中已有各种内容类型的Id如下:

    在ContentType中还一个属性为Group属性,该属性指明在本内容类型添加到网站中后,归到哪个分组下,可以在网站设置=>库下面的内容类型中看到创建成功的内容类型及其所在的组,如下:

    创建WorkFlowDelegate

    该Feature的范围是网站,为了减少Feature数量,本Feature除了实现创建委托数据列表外,还将实现其实的一些功能。在解决方案中选择添加新项,内容是WSPBuilder下的Feature with Receiver,即带后台代码的feature,在feature被激活或者停止时会触发相应的后台代码进行操作。

    创建完成后,工具除了创建了一个Feature文件夹外,还创建了一个FeatureCode文件夹,下面生成了WorkFlowDelegate.cs代码文件,在feature被激活或者停止会触发该类下的相应方法。

    Feature.xml

    由于本Feature创建的列表库中的列存在选择的Feature中,因此本Feature依赖于先前的Feature,在本feature的定义文件中添加如下代码,表示这种依赖有关系

     

    <ActivationDependency FeatureId="{641aec55-a881-4698-ab17-1d55f599ee72}"/>

     

    创建ListTemplate一般需要两个文件,一个定义文件,一个是schema文件,按上图的文件结构创建这两个文件DelegateList.xml和schema.xml文件,创建完成后,在Feature中添加对DelegateList.xml文件的引用。Feature文件最终为:

     

    Schemal.xml

    Schemal.xml文件可以到12目录下的tempate\feature中找一个拷贝过来,如12\TEMPLATE\FEATURES\CustomList\CustList这个目录,拷贝完后,修改一下ContentTypes和Fields节的内容:修改如下:

    WorkflowDelegateHandler.cs

    <ContentTypes>

    <ContentTypeRef ID="0x00B74D936CCD9648AA8DA7E81DE6819675"></ContentTypeRef>

    </ContentTypes>

    <Fields>

    <Field ID="{6323bea9-6aff-40c6-85b8-cbdd13855f22}" Type="User" Name="DelegateUser" DisplayName="用户" List="UserInfo" Required="TRUE" ShowField="ImnName" UserSelectionScope="0" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="DelegateUser" ColName="int1" />

    <Field Name="ProxyUser" Type="User" DisplayName="代理人" List="UserInfo" Required="TRUE" ShowField="ImnName" UserSelectionScope="0" ID="{60499066-90c3-4785-a099-aa04d4840108}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="ProxyUser" ColName="int2" />

    <Field Name="BeginTime" Type="DateTime" DisplayName="开始时间" Required="TRUE" Format="DateTime" IMEMode="inactive" ID="{b93bb970-9a36-40b1-8a39-8bd741813292}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="BeginTime" ColName="datetime1" CalType="0" >

    <Default>[today]</Default>

    </Field>

    <Field Name="EndTime" Type="DateTime" DisplayName="结束时间" Required="TRUE" Format="DateTime" IMEMode="inactive" ID="{d8153a32-5255-4e9e-8c67-fab307835c47}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="EndTime" ColName="datetime2" CalType="0" >

    <Default />

    </Field>

    <Field Name="WorkFlowType" Type="Text" DisplayName="流程类型" Required="FALSE" MaxLength="255" ID="{93ae19fe-f213-4214-b227-392648a7b23d}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="WorkFlowType" ColName="nvarchar3" IMEMode="">

    <Default />

    </Field>

    </Fields>

    修改完成后效果如下:

    Elements.xml

    到此列表库的模板已经创建成功,现在可以通过此模板创建实例了,在elements.xml文件中添加:

    <ListInstance Id="0"

    Description="用户委托代理数据"

    OnQuickLaunch="False"

    TemplateType="5100"

    Title="委托数据"

    Url="Lists/DelegateData" />

     

    其中TemplateType值与DelegateList.xml文件中ListTemplate的Type属性值要一致。

     

    WorkFlowDelegate.cs

    在WorkFlowDelegate.cs页面中创建Feature激活时的操作,这里的操作有两个,一是给工作流任务列表添加一个字段,叫代理人,另一个工作是修改任务列表的我的任务视图,原视图的过滤条件是分配对象=本人,改为分配对象=本人 或者 代理者=本人

     

    具体代码如下 :

    public override void FeatureActivated(SPFeatureReceiverProperties properties)

    {

    using (SPWeb web = properties.Feature.Parent as SPWeb)

    {

    if (web == null)

    {

    return;

    }

    int listNum=web.Lists.Count;

    for(int i=0;i<listNum;i++)

    {

    SPList list = web.Lists[i];

    if (list.BaseTemplate != SPListTemplateType.Tasks)

    {

    continue;

    }

    if (list.Fields.ContainsField(this.m_proxyUserFieldName))

    {

    continue;

    }

    //添加字段

    string fieldxml = string.Format("<Field Type=\"User\" Name=\"{0}\" DisplayName=\"{0}\" List=\"UserInfo\" UserSelectionScope=\"0\" />",

    this.m_proxyUserFieldName);

    list.Fields.AddFieldAsXml(fieldxml);

    SPField field = list.Fields[this.m_proxyUserFieldName];

    if (field == null)

    {

    continue;

    }

    field.Title = "代理者";

    field.Update();

    SPView myTaskView = list.Views["我的任务"];

    if (myTaskView == null)

    {

    Continue;

    }

    //更新我的任务视图

    string query = string.Format(@"<OrderBy><FieldRef Name=""Status"" /></OrderBy><Where><Or><Eq><FieldRef Name=""AssignedTo"" /><Value Type=""Integer""><UserID Type=""Integer"" /></Value></Eq><Eq><FieldRef Name=""{0}"" /><Value Type=""Integer""><UserID Type=""Integer"" /></Value></Eq></Or></Where>"

    , this.m_proxyUserFieldName);

    myTaskView.Query = query;

    myTaskView.Update();

    }

    }

    }

    创建委托菜单及处理页面

    添加委托菜单

    即在工作流任务列表的操作菜单下添加一个设置委托的菜单,完成后效果如下 :

    该步骤比较简单,可以将该功能归入WorkFlowDelegate这个Feature中,在其elements.xml加入以下代码即可:

    <CustomAction Id="DelegateAction.DelegateItem"

    RegistrationType="List"

    RegistrationId="107"

    GroupId="ActionsMenu"

    Location="Microsoft.SharePoint.StandardMenu"

    Sequence="1000"

    ImageUrl="/_layouts/images/titlegraphic.gif" Description="设置任务委托人"

    Title="设置委托">

    <UrlAction Url="javascript:window.location= '{SiteUrl}/_layouts/SetDelegate.aspx?ListId={ListId}&amp;Source='+window.location;"/>

    </CustomAction>

     

    其中:

    RegistrationId为107表示在任务列表中添加菜单,其它类型的列表库类型可以通过SDK进行查找

    UrlAction的URL中可以有一些占位符,在SDK中介绍:

    ~site - Web site (SPWeb) relative link.

    ~sitecollection - site collection (SPSite) relative link.

    In addition, you can use the following tokens within a URL:

    {ItemId} - Integer ID that represents the item within a list.

    {ListId} - GUID that represents the list.

    {SiteUrl} - URL of the Web site (SPWeb).

    {RecurrenceId} - Recurrence index. This token is not supported for use in the context menus of list items.

     

    另外还需注意一点是占位符只能被替换一次,比如说如果URL中你要使用到{SiteUrl}多次的话,那只能通过其它方式进行写了,由于URL中不仅支持链接地址,还支持javascript脚本,因此,出现了一种取巧的方法,在http://weblogs.asp.net/jan/archive/2007/09/05/using-the-current-page-url-in-the-urlaction-of-a-sharepoint-feature.asp 中有描述如何在URL中使用脚本。

    委托处理页

    在CustomAction中我们给出一该菜单的处理地址为_layouts/SetDelegate.aspx,因此下面我们就在Layout目录下创建一个这样的文件:

    只要在项目中对Microsoft.SharePoint.dll进行了引用,那们就可以直接在SetDelegate.aspx页面中,我们可以直接使用sharepiont的一些门资源了,如:sharepiont的母版页,日期控件、选人控件等。

    SetDelegate.aspx页面代码如下:

    <asp:Content ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">

    设置委托人

    </asp:Content>

    <asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <table cellpadding="5" cellspacing="1" style="background-color:Fuchsia" width="100%">

    <tr style="background-color:White">

    <td>

    开始时间

    </td>

    <td>

    <SharePoint:DateTimeControl HoursMode24="true" ID="txtDateBegin" runat="server"></SharePoint:DateTimeControl>

    </td>

    </tr>

    <tr style="background-color:White">

    <td>

    结束时间

    </td>

    <td>

    <SharePoint:DateTimeControl HoursMode24="true" ID="txtDateEnd" runat="server"></SharePoint:DateTimeControl>

    </td>

    </tr>

    <tr style="background-color:White">

    <td>

    代理者

    </td>

    <td>

    <SharePoint:PeopleEditor ID="ProxyUser" runat="server" MultiSelect="false" ShowCreateButtonInActiveDirectoryAccountCreationMode="true" SelectionSet="User" AllowEmpty="false"/>

    </td>

    </tr>

    <tr style="background-color:White">

    <td colspan="2">

    <asp:Label ID="lbErr" runat="server" Text="错误信息" Visible="false" ForeColor="Red"></asp:Label>

    <asp:Button ID="btSubmit" runat="server" Text="设置" />

    <asp:Button ID="btDelete" runat="server" Text="删除" Visible="false" />

    </td>

    </tr>

    </table>

    </asp:Content>

    由于页面不支持可视化编辑,并且不有.cs.designer页面,因此必须要在后台页面的OnInit方法中生成.aspx页面中两个控件的点击事件,代码如下:

     

    protected override void OnInit(EventArgs e)

    {

    this.btSubmit.Click += new EventHandler(btSubmit_Click);

    this.btDelete.Click += new EventHandler(btDelete_Click);

    }

     

    其它的和以前的页面处理一样,具体的业务逻辑代码就不公布出来了,大家自己写了。业务逻辑大概就是:

    PageLoad方法:

    如果用户没有设置代理,则删除操作不可用

    如果有设置代理,删除操作可用,并将已设置的代理人及时间信息读取出来,填到表单上

    btSubmit_Click:

    将代理保存到先前创建的委托数据列表库中,并且更新本任务列表库(URL中已经传入了任务列表的ID)中分配给这个的待办任务,只处理未完成的任务,已完成的任务不处理

    btDelete_Click:

    删除用户的委托代理数据,并更新任务列表中当前用户的委托代理信息

     

    创建EventHandler

    对于任务列表中的每一条待办任务创建成功后,都要检验一下对于分配对象是否有设置委托代理,如果没有设置的话,则不做处理,如果有设置的话,则修改该待办任务,填写代理者字段。

    在FeatureCode目录下创建一个WorkflowDelegateHandler.cs文件来处理该EventHandler,文件代码如下:

    class WorkflowDelegateHandler : SPItemEventReceiver

    {

    public override void ItemAdded(SPItemEventProperties properties)

    {

    base.ItemAdded(properties);

    this.DisableEventFiring();

    SPListItem item = properties.ListItem;

    using (SPWeb web = properties.OpenWeb())

    {

    SPContext context=SPContext.GetContext(web);

    int taskOwnerId = Utility.FomatUserID(item["AssignedTo"]);

    SPUser user = web.SiteUsers.GetByID(taskOwnerId);

    WorkflowDelegateBLL bll = new WorkflowDelegateBLL(user);

    bll.Context = context;

    bll.SetTaskDelegate(item);

    }

    this.EnableEventFiring();

    }

    }

     

    Elements.xml

    编写完成后,最后一步就是将该EventHandler关联到任务列表,该操作也可以用Feature来完成,打开WorkFlowDelegate的Elements.xml文件,加入:

     

    <Receivers ListTemplateId="107">

    <Receiver>

    <Name>DelegateAddingEventHandler</Name>

    <Type>ItemAdded</Type>

    <SequenceNumber>10000</SequenceNumber>

    <Assembly>MossTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0d71750f77f308af</Assembly>

    <Class> MossTest.WorkflowDelegateHandler</Class>

    <Data></Data>

    <Filter></Filter>

    </Receiver>

    </Receivers>

     

    ListTemplateId值为107,表示该操作仅对任务列表类型的列表库进行操作。其它类型列表库可以查看SDK相关文档。

     

    本文来自CSDN博客,转载请标明出处:file:///F:/SharePoint2007/Designer工作流网页/Infopath+Designer工作流设计之四--委托代理开发%20-%20北极星博客%20-%20CSDN博客.htm

  • 相关阅读:
    师弟大喜之日,送上一幅对联 求横批
    漫画:Google 走了
    产品研发流程改进
    Outlook2010 Bug 一则
    Android 手机用户版本比例
    CDMA 短信中心号码
    UIM卡 PIN 码特点
    [Accessibility] Missing contentDescription attribute on image
    java打印函数的调用堆栈
    android中解析Json
  • 原文地址:https://www.cnblogs.com/KimhillZhang/p/1529431.html
Copyright © 2020-2023  润新知