引言 SPS是一个安全可伸缩的企业级门户服务器可以利用它将SharePoint 站点信息和应用程序汇集到一个单一的门户位置用户可以通过门户内容和布局进行个性化的定制更快地找到相关信息目前许多企业和政府部门已开始基于SPS服务在互联网上提供信息共享与应用服务并构建跨企业的虚拟组织或虚拟企业以实现大规模的资源共享Web Part的自定义开发是实现基于SPS上的复杂应用的关键微软官方提供的Web Partforvs模版是开发Web Part的标准编程环境但是非常可惜它不提供Web Part开发的可视化界面对于复杂界面的Web Part的开发将是一件非常吃力的事情用户控件包装器巧妙的利用Web Partforvs模版通过Web Part的属性将用户控件载入页面通过菜单编辑用户控件通过Web Part的数据传递实现用户控件之间的数据传递 用户控件与Web Part的联系 ASPNET为扩展服务器控件框架提供了两个抽象用户控件和自定义控件 用户控件实质上是可插入其他页面中的 ASPNET 页面它们在一定程度上类似于传统 ASP 中使用的 Include 文件使用 Visual Studio NET可以使用将控件拖到页面设计器的方式将服务器控件拖到用户控件设计器上从而轻松地构建用户控件 ASPNET自定义控件实质是一个从SystemWebUIControl直接或间接继承于的类它不受Visual Studio NET中图形工具的支持可以通过覆盖SystemWebUIControl的CreateChildControls 方法往自定义控件中添加服务器控件定义其属性和事件然后覆盖Control类的Render方法(直接继承于Control类)或覆盖WebControl类的RenderContent方法(继承于WebControl类)编写自己的代码来发出 html Web Part是SPS网站上的基本单元它的概念类似于ASPNET自定义控件自己开发的Web Part将从MicrosoftSharePointWeb PartPagesWebPart类继承也是间接的继承了SystemWebUIControl类一样可以通过覆盖SystemWebUIControl的CreateChildControls方法添加服务器控件定义其属性和事件然后覆盖WebPart类的RenderWebPart方法编写自己的代码发出html Web Part可以通过添加子控件的方式将用户控件和自身相联系需要定义的大量用户界面和业务事件在用户控件中完成Web Part起着选择用户控件编辑用户控件和传递用户控件数据的作用 用户控件包装器的具体实现 用户控件的载入和属性编辑 用户控件的载入和属性编辑都借助了Web Part的属性和工具面板Web Part的属性分为默认属性和自定义属性默认属性对Web Part的外观(如标题高度宽度)布局(如所在Web Part区域显示的次序)和更高级的控制(如是否允许关闭是否允许区域更改及选择访问Web Part的群体)进行了设置是Web Part自带的属性自定义属性是用户自已定义的属性便于更灵活的编辑Web Part 工具面板由不同的Tool Part组成 默认属性对应WebPartToolPart类自定义属性对应CustomPropertyToolPart类这两个类都继承于ToolPart类WebPart类的GetToolParts方法决定将哪些Tool Part显示在工具面板里Web Part框架默认在该方法中将这两个类的实例写入ToolPart数组中这两个属性将被工具面板中对应的Tool Part所编辑同理创建继承于ToolPart的类就可以在工具面板中很好的控制Web Part中除了属性的内容 用户控件的载入 用户控件的载入通过Web Part的自定义属性和工具面板实现主要步骤如下 () 将用户控件对应的dll文件放入SPS的bin目录下以待执行 () 创建WebPart的子类 () 在子类中添加一个自定义属性用于保存载入的用户控件的完整路径 () 创建ToolPart的子类 () 将ascx文件放在SPS的某个虚拟目录下在ToolPart子类中实现从该虚拟目录获取所有用户控件信息的方法 () 在ToolPart子类中实现一个返回一个字符串的方法该字符串用于创建一个项值为用户控件完整路径项的文本为用户控件名称或描述的下拉列表框 () ToolPart的子类覆盖虚方法RenderToolPart(HtmlTextWriter)将第步得到的字符串传入并被HtmlTextWriter对象写到浏览器上用于在工具面板中显示包含所有用户控件的下拉列表框 () ToolPart的子类覆盖虚方法ApplyChanges(该虚方法用于用户点击工具面板中的确定或应用按钮时发生将相应Tool Part中的值作编辑)将通过表单形式提交到服务器端的下拉列表框的选中值传给相应Web Part的保存用户控件路径的自定义属性通过该属性载入用户控件 () WebPart的子类覆盖虚方法GetToolParts在该方法中返回的ToolPart数组中加入第步创建的类的实例 () WebPart的子类覆盖虚方法CreateChildControls将载入的用户控件作为Web Part的子控件加入 () WebPart的子类覆盖虚方法RenderWebPart通过RenderControl方法将该用户控件呈现到浏览器上 当载入用户控件后可以将用户控件属性映射到工具面板的一个Tool Part上通过Tool Part来编辑用户控件属性主要步骤如下 ()创建ToolPart的另一个子类添加一个自定义属性将载入的用户控件传给它 () WebPart的子类覆盖WebPart的虚方法GetToolParts在该方法中返回的ToolPart数组中加入第步创建的类的实例 () 创建一个编辑不同类型属性的基类将载入的用户控件及及时的http请求和要求编辑的属性传给它在该类的子类中具体实现不同类型属性的编辑基类中创建一个返回一个字符串的抽象方法该字符串是编辑属性的html控件的html标记的字符串形式在子类中对该方法进行具体实现 () 创建一个编辑用户控件所有属性的类该类利用第步创建的类逐一将编辑用户控件属性的html控件封装进一个HtmlTable中 () 第步创建的类覆盖ToolPart的虚方法RenderToolPart利用第步创建的类将对应用户控件属性信息的一个HtmlTable呈现到工具面板当中 以上步骤将用户控件的属性映射到工具面板的一个Tool Part当中以下步骤将实现通过Tool Part编辑用户控件的属性 () 在WebPart的子类中添加一个自定义属性保存用户控件的所有属性值 () 在WebPart的子类中实现一个由外部传入的属性新值更新保存属性值的自定义属性的方法 () 在WebPart的子类中实现一个利用上述自定义属性更新用户控件属性的方法 () 在编辑不同类型属性的基类中创建一个返回Object类型的抽象函数该返回值代表以表单形式提交到服务器端的编辑属性的html控件的值该抽象函数在子类中得到具体的实现 () 第步创建的类覆盖ToolPart的虚方法ApplyChanges利用第步创建的函数得到提交到服务器端的html控件值将该值传给WebPart的子类更新保存属性值的自定义属性然后利用该自定义属性更新用户控件的属性值 用户控件的编辑 菜单是Web Part的一个重要组成部分菜单的充分利用可以对Web Part的内容进行方便的编辑Web Part自带的菜单可以实现对Web Part进行有效的编辑这里介绍利用菜单实现对用户控件的复制和粘贴 确定一个用户控件的完整信息需要得到用户控件的路径及用户控件的所有属性可以考虑将这两者复制到一个剪切板上类的静态成员在该类的所有实例里拥有一样的值巧妙地起到剪切板的作用基于这个思想在WebPart的子类中添加两个静态域用于保存用户控件的信息 复制过程 () 添加复制菜单及相应菜单的服务器端函数 () 在函数中将WebPart子类中的自定义属性的值赋予添加的两个静态域 粘贴过程 () 添加粘贴菜单及相应菜单的服务器端函数 () 在函数中将两个静态域的值赋予WebPart子类的自定义属性 () 根据保存用户控件路径的自定义属性添加用户控件 () 根据保存用户控件属性的自定义属性赋予用户控件新的属性值 () 保存自定义属性的值以便再次加载页面时用户控件的状态得以保留 用户控件之间的数值传递 Web Part之间的数值传递 用户控件之间的数值传递依赖于Web Part之间的数值传递Web Part之间的数值通过实现Web Part框架提供的对接口之一得以传递这对接口分别是 连接的接口对 描述 ICellProvider ICellConsumer 由实现ICellProvider的对象提供一个Object类型的单一值给实现ICellConsumer的对象实现ICellConsumer的对象在接收值之前可以向实现ICellProvider的对象提供String类型的初始信息实现ICellProvider的对象也可以在发送值之前向实现ICellConsumer的对象提供String类型的初始信息 IRowProvider IRowConsumer 由实现IRowProvider的对象提供一个DataRow类型的数组给IRowConsumer实现IRowProvider的对象在传递值之前可以向实现IRowConsumer的对象提供String类型的初始信息 IListProvider IListConsumer 由实现IListProvider的对象提供一个DataTable类型的数给IListConsumer的对象实现IRowProvider的对象在传递值之前可以向实现IRowConsumer的对象提供String类型的初始信息 IFilterProvider IFilterConsumer 提供或者消费一个String类型的过滤值的接口对 例如SharePoint列表实现了IRowProvider IListProvider IFilterConsumer 那么两个不同的列表能够互相连接并且一个列表可以过滤另一个列表的内容 IParametersInProvider IParametersInConsumer 实现IParametersInProvider接口的对象可以向IParametersInConsumer的对象提供任意组的参数值值的内容由String类型组成实现IParametersInConsumer的对象在接受参数之前可以向实现IParametersInProvider的对象提供所需参数的初始信息 IParametersOutProvider IParametersOutConsumer 实现IParametersOutProvider接口的对象可以向IParametersOutConsumer的对象提供任意组的参数值值得内容由string类型组成实现IParametersOutProvider的对象在发送参数之前可以向实现IParametersOutConsumer的对象提供所需参数的初始信息 Web Part连接的设计和SharePoint的对象模型有紧密的联系但是从本质上说提供的数据类型分为Object和String两大类(DataRow和DataTable实际上也就是Object类型的数组组成)提供的相关信息都是String类型方向要么由数据者提供向数据者接收提前发送要么由数据者接收向数据者提供者提前发送用户控件对数据交流的最大要求是既可以传递数据又可以接收数据并且可以是任意类型的数据类型一个Web Part可以实现多个接口以实现既传递数据又接受数据的功能但是两个Web Part之间不能既提供数据给对方又从对方接受数据这样将形成闭环可以考虑的方案是传递数据而接收数据的初始化信息综上因素ICellProvider和ICellConsumer是不错的选择因为传递的数据是Object类型而接收方可以提前传递初始化信息给发送方主要实现步骤如下 () 创建供用户控件待以实现的数据提供接口和数据接收接口 () 创建两个类分别用于实现ICellProvder和ICellConsumer接口 () 在WebPart的子类中添加第步创建的类的对象作为域成员 () 在WebPart的子类中覆盖虚方法EnsureInterfaces根据包装的用户控件实现的接口类型注册ICellProvider接口或ICellConsumer接口 () 在WebPart的子类中覆盖虚方法CanRunAt指明连接的位置在服务器端还是客户端 () 在WebPart的子类中覆盖虚方法PartCommunicationConnect该方法被Web Part框架用来通知Web Part已被连接 () 在WebPart的子类中覆盖虚方法PartCommunicationInit该方法被Web Part框架用来传送初始化信息注册了ICellConsumer的Web Part可以从用户控件得到要传送的初始化信息在实现ICellConsumer的域成员中进行传送注册了ICellProvider的Web Part也可以从用户控件得到要传送的初始化信息在实现ICellProvider的域成员中进行传送 () 在WebPart的子类中覆盖虚方法PartCommunicationMain注册了ICellProvider的Web Part可以将实现ICellProvider的域成员在此方法中得到的传递过来的初始化信息转发给用户控件注册了ICellConsumer的Web Part也可以将实现ICellConsumer的域成员在此方法中得到的传递过来的初始化信息转发给用户控件同时注册了ICellProvider接口的Web Part可以在此时接收用户控件传来的数据利用实现ICellProvider的域成员发送数据给注册ICellConsumer接口的Web Part () 在WebPart的子类中覆盖虚方法RenderWebPart注册了ICellConsumer接口的Web Part的实现ICellConsumer的域成员在此方法中得到注册了ICellProvider的Web Part传来的数据注册了ICellConsumer接口的Web Part可以将数据传递给包装的用户控件将用户控件呈现在浏览器上 这些虚方法都是Web Part框架依次调用次序和步骤顺序一致 结束语 用户控件包装器是巧妙的利用Web Part本身的功能将Web Part的缺陷加以克服它的实现给Web Part的开发带来极大的便利ASPNET程序员根本就不需要理解Web Part的开发原理就可以利用以往的编程思想快速地开发自己需要的Web Part进而使得SPS的门户网站开发和设计事半功倍 |