【原创】SharePoint2010的SaveButton如何实现在跳转前给用户以提示[How to implement SaveButton display an alert when Redirect action]
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
Technorati 标签: SharePoint,SaveButton
一点说明:为什么在标题中要嵌入英文?原因是为了能够让国外的网友能查询到这篇文章。平常在Google上查资料的时候,经常参考国外网友的博客,帮助我解决了很多问题,所以我也想让他们能够参考我写的内容。当然文中我不可能全部译为英文,所以我尽量把代码粘全,靠代码说话吧。