SharePoint 2010 的SaveButton控件在保存数据后,会跳转到Url参数中的Source指定的页面,如要没有Source则跳转到List的默认页面。有的时候,需要在保存后能够给用户一个提示再进行跳转,这就要修改SaveButton的默认行为,当然最简单的方式就是继承SaveButton,然后进行客户端方式的跳转。幸运的是,SaveButton并非是定义为sealed的,所以继承是没有问题的,所以我定义了SaveButtonEx类。
public class SaveButtonEx : Microsoft.SharePoint.WebControls.SaveButton
定义两个属性,定义是否为客户端跳转
/// <summary>
/// 是否是客户端跳转
/// </summary>
public Boolean IsClientRedirect
{
get;
set;
}
/// <summary>
/// 跳转前的消息
/// </summary>
public string RedirectMessage
{
get;
set;
}
关键的地方在于能够重写其被Click时候的行为,本质上SaveButton并不是直接继承的Button控件,而是通过在CreateChildControls中包装了Button控件实现的,所以要重写的方法是OnBubbleEvent,而不是OnClick.
[SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
protected override bool OnBubbleEvent(object source, EventArgs e)
{
bool flag = false;
if (e is CommandEventArgs)
{
CommandEventArgs args = (CommandEventArgs)e;
if (!(args.CommandName == "SaveItem"))
{
return flag;
}
SPListItem listItem = base.ItemContext.ListItem;
SPContentType contentType = ReflectorUtils.getPerperty<SPContentType>("ContentType", base.ItemContext);
if (((listItem != null) && (contentType != null)) && !ReflectorUtils.getPerperty<bool>("HasExternalDataSource", listItem))
{
try
{
listItem["ContentType"] = contentType.Name;
ReflectorUtils.InvokeMethod(listItem, "SetExtraInfo", new object[] { "ContentTypeId", contentType.Id.ToString(), "" });
}
catch (ArgumentException)
{
}
}
this.Page.Validate();
if (!this.Page.IsValid)
{
return true;
}
bool flag2 = false;
EventHandler onSaveHandler = base.ItemContext.FormContext.OnSaveHandler;
if (onSaveHandler != null)
{
ReflectorUtils.InvokeMethod(typeof(Microsoft.SharePoint.WebControls.SaveButton), null, "ActionBeforeSaveItem", new object[] { ItemContext });
onSaveHandler(this, EventArgs.Empty);
flag2 = ((ReflectorUtils.getPerperty<object>("FieldValidationFailures", base.ItemContext.FormContext) == null)
&& (ReflectorUtils.getPerperty<object>("ItemValidationFailure", base.ItemContext.FormContext) == null))
&& (ReflectorUtils.getPerperty<object>("UniqueFieldsWithDuplicateValues", base.ItemContext.FormContext) == null);
}
else if (base.List.BaseTemplate == SPListTemplateType.Survey)
{
if (ReflectorUtils.getPerperty<object>("NextFieldName", base.ItemContext.FormContext) == null)
{
ReflectorUtils.InvokeMethod(listItem, "Checkin", null);
flag2 = true;
}
else if (base.ControlMode == SPControlMode.New)
{
ReflectorUtils.InvokeMethod(listItem, "Checkout", null);
flag2 = true;
}
else
{
flag2 = this.SaveItem();
}
}
else
{
flag2 = this.SaveItem();
}
flag = true;
if (!flag2)
{
return flag;
}
string redirectUrl = base.RedirectUrl;
ReflectorUtils.setPerperty("InSavePostBack", base.ItemContext, true, null); //这里特别要测试一下会不会有异常
bool needToCreateWorkSpace = (bool)ReflectorUtils.InvokeMethod(typeof(Microsoft.SharePoint.WebControls.SaveButton), this, "NeedToCreateWorkSpace", new object[] { });
if (needToCreateWorkSpace)
{
ReflectorUtils.InvokeMethod(typeof(Microsoft.SharePoint.WebControls.SaveButton), this, "GotoMeetingWorkspaceCreationPage", new object[] { redirectUrl });
return flag;
}
if (!base.ItemContext.IsPopUI)
{
if (base.ItemContext.List.BaseType == SPBaseType.DocumentLibrary)
{
SPFile file = ((SPListItem)base.Item).File;
if (file != null)
{
redirectUrl = file.ServerRelativeUrl;
}
else
{
SPFolder folder = ((SPListItem)base.Item).Folder;
if (folder != null)
{
redirectUrl = folder.ServerRelativeUrl;
}
else
{
redirectUrl = ReflectorUtils.getPerperty<string>("RootFolderUrl", base.ItemContext.List);
}
}
}
if (!this.IsClientRedirect)
{
SPUtility.Redirect(redirectUrl, SPRedirectFlags.UseSource, this.Context);
}
else
{
this.Context.Response.Write(
"<script type='text/javascript'>alert('" + this.RedirectMessage +
"');window.location.href='" + redirectUrl + "';</script>");
this.Context.Response.Flush();
this.Context.Response.End();
}
return flag;
}
if ((listItem != null) && (listItem.File != null))
{
string serverRelativeUrl = listItem.File.ServerRelativeUrl;
this.Context.Response.Write(string.Format(CultureInfo.InvariantCulture, "<script type='text/javascript'>\r\n retVal = {{}};\r\n retVal['newFileUrl'] = \"{0}\";\r\n window.frameElement.commitPopup(retVal);\r\n </script>", new object[] { serverRelativeUrl }));
}
else
{
this.Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
}
this.Context.Response.Flush();
this.Context.Response.End();
}
return flag;
}
当然,这里面的大部分代码我只是从反编译的代码中复制过来的.其中涉及到一些internal的private的方法及属性,需要使用反射的方式进行调用。
对于跳转的方法其实就很简单了,就是判断是否为客户端跳转,是的话就注册一段脚本,输出alert以及通过window对象进行跳转。下面是这段代码
if (!this.IsClientRedirect)
{
SPUtility.Redirect(redirectUrl, SPRedirectFlags.UseSource, this.Context);
}
else
{
this.Context.Response.Write(
"<script type='text/javascript'>alert('" + this.RedirectMessage +
"');window.location.href='" + redirectUrl + "';</script>");
this.Context.Response.Flush();
this.Context.Response.End();
}
下面是反射辅助类的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Only.SPLibraryExtend.Utils
{
/// <summary>
/// 反射工具
/// </summary>
public class ReflectorUtils
{
public static void setField(Type type,string fieldName, object o, object value)
{
FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(o, value);
}
public static void setField(string fieldName,object o,object value)
{
setField(o.GetType(), fieldName, o, value);
}
public static T getField<T>(Type type,string fieldName, object o)
{
T result = default(T);
FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
result = (T)fi.GetValue(o);
return result;
}
public static T getField<T>(string fieldName, object o)
{
return getField<T>(o.GetType(), fieldName, o);
}
/// <summary>
/// 获取反射的属性
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="property"></param>
/// <param name="o"></param>
/// <returns></returns>
public static T getPerperty<T>(string property, object o)
{
T result;
Type t = o.GetType();
PropertyInfo pi = t.GetProperty(property, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic);
result = (T)pi.GetValue(o, null);
return result;
}
public static void setPerperty(string property, object o,object value,object[] index)
{
Type t = o.GetType();
PropertyInfo pi = t.GetProperty(property, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetProperty);
pi.SetValue(o, value, index);
}
public static object InvokeMethod(object target, string methodName, object[] parameters)
{
return InvokeMethod(target.GetType(), target, methodName, parameters);
}
/// <summary>
/// 反射调用非重载方法
/// </summary>
/// <param name="t"></param>
/// <param name="target"></param>
/// <param name="methodName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static object InvokeMethod(Type t, object target, string methodName, object[] parameters)
{
MethodInfo method = null;
if (target == null)
{
method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
}
else
{
method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
var result = method.Invoke(target, parameters);
return result;
}
/// <summary>
/// 反射调用重载的方法
/// </summary>
/// <param name="t"></param>
/// <param name="target"></param>
/// <param name="methodName"></param>
/// <param name="parameters"></param>
/// <param name="parameterTypes"></param>
/// <returns></returns>
public static object InvokeMethod(Type t, object target, string methodName, object[] parameters, Type[] parameterTypes)
{
MethodInfo method = null;
if (target == null)
{
method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, Type.DefaultBinder, parameterTypes, null);
}
else
{
method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, parameterTypes, null);
}
var result = method.Invoke(target, parameters);
return result;
}
}
}
这个控件的运行效果,请参见:http://www.cnblogs.com/fxwdl/archive/2012/08/30/2663182.html