WSS页面定制系列(3)---重写表单的保存逻辑

    通过上一篇文章 WSS页面定制系列(2)---定制单个列表的表单页面您应该了解到了如何定制列表那些查看,新增,修改的页面。但是只限于页面布局。
如果需要修改保存逻辑应该怎么做呢?
     这个需求还是很常见的,比如,保存之前做一些校验,保存之后重定向到某个页面。
     系统模板里面负责保存操作的是如下的控件:
< SharePoint:SaveButton  runat ="server" />
这个控件位于Microsoft.SharePoint.WebControls名称控件。我们用reflector找到关键代码:

[SharePointPermission(SecurityAction.Demand, ObjectModel=true)]
protected override bool OnBubbleEvent(object source, EventArgs e)
{
    SPListItem listItem;
    string redirectUrl;
    bool flag = false;
    if (e is CommandEventArgs)
    {
        CommandEventArgs args = (CommandEventArgs) e;
        if (!(args.CommandName == "SaveItem"))
        {
            return flag;
        }
        listItem = base.ItemContext.ListItem;
        if ((listItem != null) && (base.ItemContext.ContentType != null))
        {
            try
            {
                listItem["ContentType"] = base.ItemContext.ContentType.Name;
                listItem.SetExtraInfo("ContentTypeId", base.ItemContext.ContentType.Id.ToString(), "");
            }
            catch (ArgumentException)
            {
            }
        }
    }
    else
    {
        return flag;
    }
    this.Page.Validate();
    if (this.Page.IsValid)
    {
        bool flag2 = false;
        EventHandler onSaveHandler = base.ItemContext.FormContext.OnSaveHandler;
        if (onSaveHandler == null)
        {
            if (base.List.BaseTemplate != SPListTemplateType.Survey)
            {
                flag2 = this.SaveItem();
            }
            else if (base.ItemContext.FormContext.NextFieldName != null)
            {
                if (base.ControlMode != SPControlMode.New)
                {
                    flag2 = this.SaveItem();
                }
                else
                {
                    listItem.Checkout();
                    flag2 = true;
                }
            }
            else
            {
                listItem.Checkin();
                flag2 = true;
            }
        }
        else
        {
            onSaveHandler(this, EventArgs.Empty);
            flag2 = true;
        }
        flag = true;
        if (!flag2)
        {
            return flag;
        }
        redirectUrl = base.RedirectUrl;
        if (((base.ItemContext.List.BaseTemplate == SPListTemplateType.Events) || ((base.ItemContext.ContentType != null) && base.ItemContext.ContentType.Id.IsChildOf(SPBuiltInContentTypeId.Event))) && base.ItemContext.FormContext.WantRedirectForMWS)
        {
            if ((base.ItemContext.FormContext.FormMode == SPControlMode.New) && base.ItemContext.FormContext.NeedIDForNewMWS)
            {
                redirectUrl = redirectUrl + "
&Item=" + base.ItemContext.ListItem.ID.ToString(CultureInfo.InvariantCulture);
            }
            SPUtility.Redirect(redirectUrl, SPRedirectFlags.Default, this.Context);
            return flag;
        }
    }
    else
    {
        return true;
    }
    if (base.ItemContext.List.BaseTemplate == SPListTemplateType.WebPageLibrary)
    {
        redirectUrl = ((SPListItem) base.Item).File.ServerRelativeUrl;
    }
    SPUtility.Redirect(redirectUrl, SPRedirectFlags.UseSource, this.Context);
    return flag;
}

 

 

SaveItem

DefaultTemplateName

SaveButton 控件也是采用模板实现的,它的模板如下
< SharePoint:RenderingTemplate  ID ="SaveButton"  runat ="server" >
    
< Template >          < TABLE  cellpadding =0  cellspacing =0  width =100% >< TR >< TD  align ="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,multipages_direction_right_align_value%>' EncodeMethod='HtmlEncode'/>"   width =100%  nowrap >
          
< asp:Button  UseSubmitBehavior ="false"  ID =diidIOSaveItem  CommandName ="SaveItem"  Text ="<%$Resources:wss,tb_save%>"  class ="ms-ButtonHeightWidth"  accesskey ="<%$Resources:wss,tb_save_AK%>"  target ="_self"  runat ="server" />
        
</ TD >   </ TR >   </ TABLE >
    
</ Template >
</ SharePoint:RenderingTemplate >

    这里有一点有趣的东西,SaveButton利用了asp.net里面的事件冒泡机制,即子控件产生事件(就是那个 CommandName ="SaveItem"
的Button
),但并不处理,而是把事件“冒上去”,由父控件进行拦截处理(OnBubbleEvent方法)。
(既然是这样,我们用一个图片按钮来取代那个diidIOSaveItem应该也是可以的,只要ID和CommandName不变。)

言归正传---------------我第一次看到SaveButton控件的核心代码的时候,感到有点晕,太复杂了~ 而且,里面的很多内部方法都是私有的!
怎么改?
一种方法:继承SaveButton,重载OnBubbleEvent方法。对私有的方法,我们全部采用反射来调用。
这种方法其实是可行的,但是好像有一点“丑陋”。
第二种方法:我们是不是可以简化它的代码?我们重写的按钮只是用在有限的地方,不需要考虑的那么全面。

当我闷头探索第二种方法的时候,想到了第三种方法--我不要管它原来的代码,只接调用ListItem的Add方法不行吗?只要取到当前的所有字段,遍历即可。
取列表的所有字段,可以调用基类的 this.ItemContext.FormContext.FieldControlCollection类获得。

下面是实现代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using System.Web.UI;
 
using Microsoft.SharePoint.WebControls;
using System.Security.Permissions;
using Microsoft.SharePoint.Utilities

namespace CodeArt.SharePoint
{
    /// 
< summary >
    /// 列表表单保存按钮,保存后返回本页面, 
    /// 
</ summary >
    public class FormSaveButton : SaveButton
    {
        //return true stop event bubble
        //return false cotinue     
        protected override bool OnBubbleEvent(object source, EventArgs e)
        {
            this.Page.Validate();

            if (!this.Page.IsValid)
            {
                return true ;
            }
               //some valid code

            try
            {
                SaveData();
                return true ; 
            }
            catch (Exception ex)
            {               
                throw new SPException(ex.Message,ex);
            }

Page.Response.Redirect("/");

        }

        void SaveData()
        {            
            SPListItem listItem;

            if (this.ControlMode == SPControlMode.New)
                listItem = this.List.Items.Add();
            else
                listItem = this.ListItem;

            foreach (BaseFieldControl f in this.ItemContext.FormContext.FieldControlCollection)
            {
                try
                {
                      //some valid code here --if(f.FieldName="XX") do something...

                    if (!f.Field.ReadOnlyField)
                        listItem[f.FieldName] = f.Value;
                }
                catch (ArgumentException) { }
            }

            listItem.Update();   
        }              
    }
}

这个 FormSaveButton 的保存前后的行为可以由我们任意控制了。把它编译成dll,然后嵌入RenderingTemplate即可。

附:
SaveButton,FormField这类控件可以称为“表单控件”,它们实现对列表表单的操作,或者是呈现一个字段,后者是显示一个保存按钮,或者是来迭代生成页面。
它们的继承关系如下:

SaveButton 》 FormComponent 》 TemplateBasedControl》SPControl》 Control

FormField 》 BaseFieldControl 》 FieldMetadata》FormComponent
》 TemplateBasedControl 》SPControl》 Control

所有的 “表单控件”都继承于 TemplateBasedControl,都可以通过修改模板或重载替换已有控件来控制它的内容。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值