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,都可以通過修改模板或重載替換已有控件來控制它的內容。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章