How do you handle multiple submit buttons in ASP.NET MVC Framework?
是否有一些简单的方法来处理同一表单中的多个提交按钮?例子:
1 2 3 4 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <input type="submit" value="Send" /> <input type="submit" value="Cancel" /> <% Html.EndForm(); %> |
知道如何在ASP.NET框架测试版中执行此操作吗?我在谷歌上搜索到的所有例子都有一个按钮。
这里是一个基于属性的多提交按钮问题的解决方案,主要基于Maartin Balliauw的文章和评论。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class MultipleButtonAttribute : ActionNameSelectorAttribute { public string Name { get; set; } public string Argument { get; set; } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { var isValidName = false; var keyValue = string.Format("{0}:{1}", Name, Argument); var value = controllerContext.Controller.ValueProvider.GetValue(keyValue); if (value != null) { controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument; isValidName = true; } return isValidName; } } |
剃刀:
1 2 3 4 | <form action="" method="post"> <input type="submit" value="Save" name="action:Save" /> <input type="submit" value="Cancel" name="action:Cancel" /> </form> |
和控制器:
1 2 3 4 5 6 7 | [HttpPost] [MultipleButton(Name ="action", Argument ="Save")] public ActionResult Save(MessageModel mm) { ... } [HttpPost] [MultipleButton(Name ="action", Argument ="Cancel")] public ActionResult Cancel(MessageModel mm) { ... } |
更新:Razor页面看起来提供了开箱即用的相同功能。对于新的发展,这可能更可取。
为提交按钮命名,然后在控制器方法中检查提交的值:
1 2 3 4 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <input type="submit" name="submitButton" value="Send" /> <input type="submit" name="submitButton" value="Cancel" /> <% Html.EndForm(); %> |
张贴到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class MyController : Controller { public ActionResult MyAction(string submitButton) { switch(submitButton) { case"Send": // delegate sending to another controller action return(Send()); case"Cancel": // call another action to perform the cancellation return(Cancel()); default: // If they've submitted the form without a submitButton, // just return the view again. return(View()); } } private ActionResult Cancel() { // process the cancellation request here. return(View("Cancelled")); } private ActionResult Send() { // perform the actual send operation here. return(View("SendConfirmed")); } } |
编辑:
要扩展此方法以使用本地化站点,请在其他地方隔离消息(例如,将资源文件编译为强类型资源类)
然后修改代码,使其工作方式如下:
1 2 3 4 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" /> <input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" /> <% Html.EndForm(); %> |
你的控制器应该是这样的:
1 2 3 4 5 6 7 8 9 10 11 | // Note that the localized resources aren't constants, so // we can't use a switch statement. if (submitButton == Resources.Messages.Send) { // delegate sending to another controller action return(Send()); } else if (submitButton == Resources.Messages.Cancel) { // call another action to perform the cancellation return(Cancel()); } |
您可以像前面提到的那样检查操作中的名称,但是您可以考虑这是否是一个好的设计。考虑到操作的责任是一个好主意,不要将这种设计与按钮名等UI方面耦合太多。因此,考虑使用两种形式和两种行动:
1 2 3 4 5 6 7 | <% Html.BeginForm("Send","MyController", FormMethod.Post); %> <input type="submit" name="button" value="Send" /> <% Html.EndForm(); %> <% Html.BeginForm("Cancel","MyController", FormMethod.Post); %> <input type="submit" name="button" value="Cancel" /> <% Html.EndForm(); %> |
另外,在"取消"的情况下,您通常不处理表单,而是转到一个新的URL。在这种情况下,您根本不需要提交表单,只需要一个链接:
1 | <%=Html.ActionLink("Cancel","List","MyController") %> |
艾伦建议你可以这样做:
If you have more than one button you
can distinguish between them by giving
each button a name:
1
2 <input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />In your controller action method you
can add parameters named after the
HTML input tag names:
1
2
3 public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }If any value gets posted to one of
those parameters, that means that
button was the one that got clicked.
The web browser will only post a value
for the one button that got clicked.
All other values will be null.
1
2 if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }
我喜欢这个方法,因为它不依赖于Submit按钮的Value属性,这个属性比分配的名称更容易更改,并且不需要启用javascript。
见:http://forums.asp.net/p/1369617/2865166.aspx_2865166
刚刚写了一篇关于这个的文章:使用ASP.NET MVC的多个提交按钮:
基本上,我不使用
所以有我的课(顺便说一句,我不太喜欢这个名字):
1 2 3 4 5 6 7 8 9 10 11 12 | public class HttpParamActionAttribute : ActionNameSelectorAttribute { public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase)) return true; if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase)) return false; var request = controllerContext.RequestContext.HttpContext.Request; return request[methodInfo.Name] != null; } } |
要使用,只需定义这样的表单:
1 2 3 4 5 | <% using (Html.BeginForm("Action","Post")) { %> <!— …form fields… --> <input type="submit" name="saveDraft" value="Save Draft" /> <input type="submit" name="publish" value="Publish" /> <% } %> |
和两种方法的控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class PostController : Controller { [HttpParamAction] [AcceptVerbs(HttpVerbs.Post)] public ActionResult SaveDraft(…) { //… } [HttpParamAction] [AcceptVerbs(HttpVerbs.Post)] public ActionResult Publish(…) { //… } } |
如您所见,该属性根本不要求您指定任何内容。此外,按钮的名称直接转换为方法名称。另外(我还没试过)这些应该也能正常工作,所以你可以发布到它们中的任何一个。直接。
我建议有兴趣的人看看马顿·巴利亚乌的解决方案。我觉得它很优雅。
如果链接不起作用,它将使用应用于控制器操作的
它很短,套房:
It was answered by Jeroen Dop
1 2 | <input type="submit" name="submitbutton1" value="submit1" /> <input type="submit" name="submitbutton2" value="submit2" /> |
在代码behinde中这样做
1 2 3 4 5 6 7 8 | if( Request.Form["submitbutton1"] != null) { // Code for function 1 } else if(Request.Form["submitButton2"] != null ) { // code for function 2 } |
祝你好运。
您应该能够命名按钮并给它们一个值;然后将这个名称作为参数映射到操作。或者,使用2个单独的动作链接或2个表单。
你可以写:
1 2 3 4 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <input type="submit" name="button" value="Send" /> <input type="submit" name="button" value="Cancel" /> <% Html.EndForm(); %> |
然后在页面中检查name=="send"或name=="cancel"…
关于actionselectname,我不喜欢的一点是,控制器中的每个action方法都会调用isvalidname;我不知道它为什么这样工作。我喜欢一个解决方案,每个按钮都有一个不同的名称,基于它的功能,但我不喜欢这样一个事实,即在操作方法中必须有与表单中按钮一样多的参数。我已经为所有按钮类型创建了枚举:
1 2 3 4 5 6 | public enum ButtonType { Submit, Cancel, Delete } |
我使用的不是actionselectname,而是actionfilter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class MultipleButtonsEnumAttribute : ActionFilterAttribute { public Type EnumType { get; set; } public MultipleButtonsEnumAttribute(Type enumType) { EnumType = enumType; } public override void OnActionExecuting(ActionExecutingContext filterContext) { foreach (var key in filterContext.HttpContext.Request.Form.AllKeys) { if (Enum.IsDefined(EnumType, key)) { var pDesc = filterContext.ActionDescriptor.GetParameters() .FirstOrDefault(x => x.ParameterType == EnumType); filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key); break; } } } } |
筛选器将在表单数据中查找按钮名称,如果按钮名称与枚举中定义的任何按钮类型匹配,则将在操作参数中查找ButtonType参数:
1 2 3 4 5 6 7 8 9 10 | [MultipleButtonsEnumAttribute(typeof(ButtonType))] public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model) { if (button == ButtonType.Cancel) { return RedirectToAction("Index","Home"); } //and so on return View(model) } |
然后在视图中,我可以使用:
1 2 | <input type="submit" value="Button Cancel" name="@ButtonType.Cancel" /> <input type="submit" value="Button Submit" name="@ButtonType.Submit" /> |
以下是最适合我的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <input type="submit" value="Delete" name="onDelete" /> <input type="submit" value="Save" name="onSave" /> public ActionResult Practice(MyModel model, string onSave, string onDelete) { if (onDelete != null) { // Delete the object ... return EmptyResult(); } // Save the object ... return EmptyResult(); } |
如果您对HTML 5的使用没有限制,可以使用带有
1 2 3 4 5 6 | <form action="demo_form.asp" method="get"> First name: <input type="text" name="fname" /><br /> Last name: <input type="text" name="lname" /><br /> <button type="submit">Submit</button><br /> <button type="submit" formaction="demo_admin.asp">Submit as admin</button> </form> |
参考:http://www.w3schools.com/html5/att_button-foraction.asp
如果您的浏览器支持输入按钮的属性形式(即10+,不确定其他浏览器),那么以下内容应该有效:
1 2 3 4 5 6 7 8 | @using (Html.BeginForm()){ //put form inputs here <input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" /> <input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") /> } |
我也遇到过这个"问题",但通过添加
http://www.w3.org/tr/html401/interact/forms.html h-17.13.2
- …
- 如果表单包含多个提交按钮,则只有激活的提交按钮成功。
- …
这意味着以下代码
1 2 3 4 5 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <input type="submit" name="send" value="Send" /> <input type="submit" name="cancel" value="Cancel" /> <input type="submit" name="draft" value="Save as draft" /> <% Html.EndForm(); %>` |
在接收端,您只需要检查您已知的提交类型是否不是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public ActionResult YourAction(YourModel model) { if(Request["send"] != null) { // we got a send }else if(Request["cancel"]) { // we got a cancel, but would you really want to post data for this? }else if(Request["draft"]) { // we got a draft } } |
有三种方法可以解决上述问题
下面是一段视频,以演示的方式总结了这三种方法。
Video :- How to handle multiple submit buttons in MVC ?
Video :- How to handle multiple submit buttons in MVC ?Do not miss our upcoming MVC training in mumbai http://stepbystepschools.net/?page_id=315
由 Shivprasad Koirala 发布于 2015年5月20日周三
HTML方式:
在HTML中,我们需要创建两个表单,并将"提交"按钮放在每个表单中。每种形式的行为都会指向不同的/各自的行为。您可以看到下面的代码:第一个表单发布到"action1",第二个表单将发布到"action2",具体取决于单击了哪个"提交"按钮。
1 2 3 4 5 6 7 | <form action="Action1" method=post> <input type="submit" name="Submit1"/> </form> <form action="Action2" method=post> <input type="submit" name="Submit2"> </form> |
AJAX方式:
如果你是一个Ajax爱好者,第二个选择会让你更兴奋。以Ajax的方式,我们可以创建两个不同的函数"fun1"和"fun1",见下面的代码。这些函数将使用jquery或任何其他框架进行Ajax调用。每个函数都与"提交"按钮的"onclick"事件绑定在一起。每个函数都调用各自的操作名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <Script language="javascript"> function Fun1() { $.post("/Action1",null,CallBack1); } function Fun2() { $.post("/Action2",null,CallBack2); } <form action="/Action1" method=post> <input type=submit name=sub1 onclick="Fun2()"/> </form> <form action="/Action2" method=post> <input type=submit name=sub2 onclick="Fun1()"/> </form> |
使用"actionnameselectorattribute":。-
这是一个很好而且很干净的选择。"actionnameselectorattribute"是一个简单的属性类,我们可以在其中编写决策逻辑,决定可以执行哪个操作。
所以第一件事是在HTML中,我们需要在提交按钮上放置适当的名称,以便在服务器上识别它们。
您可以看到,我们在按钮名称中添加了"保存"和"删除"。此外,您还可以注意到,在操作中,我们只将控制器名称"customer"而不是特定的操作名称。我们希望动作名称将由"actionnameselectorattribute"决定。
1 2 3 4 | <form action="Customer" method=post> <input type=submit value="Save" name="Save" /> <br /> <input type=submit value="Delete" name="Delete"/> </form> |
因此,当单击提交按钮时,它首先点击"actionnameselector"属性,然后根据激发哪个提交来调用适当的操作。
因此,第一步是创建一个继承自"actionnameselectorattribute"类的类。在这个类中,我们创建了一个简单的属性"name"。
我们还需要重写返回true或flase的"isvalidname"函数。这个函数是我们编写逻辑的地方,不管一个动作是否必须执行。因此,如果该函数返回true,那么将执行该操作,否则将不执行该操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class SubmitButtonSelector : ActionNameSelectorAttribute { public string Name { get; set; } public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo) { // Try to find out if the name exists in the data sent from form var value = controllerContext.Controller.ValueProvider.GetValue(Name); if (value != null) { return true; } return false; } } |
上述功能的主要核心在下面的代码中。"ValueProvider"集合包含从表单中发布的所有数据。因此,它首先查找"name"值,如果在HTTP请求中找到该值,则返回true,否则返回false。
1 2 3 4 5 6 | var value = controllerContext.Controller.ValueProvider.GetValue(Name); if (value != null) { return true; } return false; |
然后可以在相应的操作上修饰这个属性类,并提供相应的"名称"值。因此,如果提交正在执行此操作,并且名称与HTML提交按钮名称匹配,则会进一步执行该操作,否则不会执行该操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class CustomerController : Controller { [SubmitButtonSelector(Name="Save")] public ActionResult Save() { return Content("Save Called"); } [SubmitButtonSelector(Name ="Delete")] public ActionResult Delete() { return Content("Delete Called"); } } |
这是我将使用的技术,我在这里还没有看到它。链接(由Saajid Ismail发布))激发此解决方案的是http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc多个按钮,格式相同。它使Dylan Beattie的答案能够毫无问题地进行本地化。
观点:
1 2 3 4 | <% Html.BeginForm("MyAction","MyController", FormMethod.Post); %> <button name="button" value="send"><%: Resources.Messages.Send %></button> <button name="button" value="cancel"><%: Resources.Messages.Cancel %></button> <% Html.EndForm(); %> |
在控制器中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class MyController : Controller { public ActionResult MyAction(string button) { switch(button) { case"send": this.DoSend(); break; case"cancel": this.DoCancel(); break; } } } |
大卫·芬德利在他的ASP.NET博客上写了三种不同的选择。
以相同的形式阅读文章中的多个按钮,看看他的解决方案,以及每个按钮的优缺点。imho他提供了一个非常优雅的解决方案,可以利用你用来装饰动作的属性。
此脚本允许指定一个数据表单操作属性,该属性将在所有浏览器中用作HTML5表单操作属性(以一种不引人注目的方式):
1 2 3 4 5 6 | $(document).on('click', '[type="submit"][data-form-action]', function(event) { var $this = $(this), var formAction = $this.attr('data-form-action'), $form = $($this.closest('form')); $form.attr('action', formAction); }); |
包含按钮的表单将发布到数据表单操作属性中指定的URL:
1 | <button type="submit" data-form-action="different/url">Submit</button> |
这需要jquery 1.7。对于以前的版本,您应该使用
下面是我编写的一个扩展方法,用于处理多个图像和/或文本按钮。
这是图像按钮的HTML:
1 2 | <input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" type="image"> |
或者对于文本提交按钮:
1 2 | <input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart" /> <input type="submit" class="ui-button red" name="Submit_Skip" value="Not today" /> |
这里是您使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public static class FormCollectionExtensions { public static string GetSubmitButtonName(this FormCollection formCollection) { return GetSubmitButtonName(formCollection, true); } public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError) { var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault(); var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault(); if (textButton != null) { return textButton.Substring("Submit_".Length); } // we got something like AddToCart.x if (imageButton != null) { return imageButton.Substring(0, imageButton.Length - 2); } if (throwOnError) { throw new ApplicationException("No button found"); } else { return null; } } } |
注意:对于文本按钮,必须在名称前面加上
我没有足够的代表在正确的地方发表评论,但是我花了一整天的时间来讨论这个问题,所以我想和大家分享一下。
当试图实现"多按钮属性"解决方案时,
原来我引用的是System.Web.MVC版本3.0,当时它应该是4.0(其他程序集是4.0)。我不知道为什么我的项目没有正确升级,我没有其他明显的问题。
所以如果你的
我很晚才去参加聚会,但现在…我的实现借用了@mkoziki,但需要更少的硬编码字符串才能出错。需要框架4.5+。本质上,控制器方法名应该是路由的关键。
标记。按钮名称必须用
(请注意,使用C 6名称的API,为您希望调用的控制器方法的名称提供特定于类型的引用。
1 2 3 4 5 | <form> ... form fields .... <button name="action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type="submit" formmethod="post">Fund Death Star</button> <button name="action:@nameof(MyApp.Controllers.MyController.HireBoba)" type="submit" formmethod="post">Hire Boba Fett</button> </form> |
控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace MyApp.Controllers { class MyController { [SubmitActionToThisMethod] public async Task<ActionResult> FundDeathStar(ImperialModel model) { await TrainStormTroopers(); return View(); } [SubmitActionToThisMethod] public async Task<ActionResult> HireBoba(ImperialModel model) { await RepairSlave1(); return View(); } } } |
属性魔法。注意使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class SubmitActionToThisMethodAttribute : ActionNameSelectorAttribute { public SubmitActionToThisMethodAttribute([CallerMemberName]string ControllerMethodName ="") { controllerMethod = ControllerMethodName; actionFormat = string.Concat(actionConstant,":", controllerMethod); } const string actionConstant ="action"; readonly string actionFormat; readonly string controllerMethod; public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { var isValidName = false; var value = controllerContext.Controller.ValueProvider.GetValue(actionFormat); if (value != null) { controllerContext.Controller.ControllerContext.RouteData.Values[actionConstant] = controllerMethod; isValidName = true; } return isValidName; } } |
这是我发现的最好的方法:
http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | /// <summary> /// ActionMethodSelector to enable submit buttons to execute specific action methods. /// </summary> public class AcceptParameterAttribute : ActionMethodSelectorAttribute { /// <summary> /// Gets or sets the value to use to inject the index into /// </summary> public string TargetArgument { get; set; } /// <summary> /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller. /// </summary> public string Action { get; set; } /// <summary> /// Gets or sets the regular expression to match the action. /// </summary> public string ActionRegex { get; set; } /// <summary> /// Determines whether the action method selection is valid for the specified controller context. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="methodInfo">Information about the action method.</param> /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns> public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } Func<NameValueCollection> formGetter; Func<NameValueCollection> queryStringGetter; ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter); var form = formGetter(); var queryString = queryStringGetter(); var req = form.AllKeys.Any() ? form : queryString; if (!string.IsNullOrEmpty(this.ActionRegex)) { foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture))) { if (key.Contains(":")) { if (key.Split(':').Count() == this.ActionRegex.Split(':').Count()) { bool match = false; for (int i = 0; i < key.Split(':').Count(); i++) { if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0])) { match = true; } else { match = false; break; } } if (match) { return !string.IsNullOrEmpty(req[key]); } } } else { if (Regex.IsMatch(key, this.Action + this.ActionRegex)) { return !string.IsNullOrEmpty(req[key]); } } } return false; } else { return req.AllKeys.Contains(this.Action); } } } |
享受一个代码气味较少的多提交按钮未来。
谢谢您
我试图综合所有的解决方案,并创建了一个[Buttenhandler]属性,使处理表单上的多个按钮变得容易。
我已经在ASP.NET MVC中的codeproject多参数化(可本地化)表单按钮上描述过它。
要处理此按钮的简单情况:
1 | <button type="submit" name="AddDepartment">Add Department</button> |
您将使用以下操作方法:
1 2 3 4 5 6 | [ButtonHandler()] public ActionResult AddDepartment(Company model) { model.Departments.Add(new Department()); return View(model); } |
注意按钮的名称如何与操作方法的名称匹配。本文还描述了如何使用带有值的按钮和带有索引的按钮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | //model public class input_element { public string Btn { get; set; } } //views--submit btn can be input type also... @using (Html.BeginForm()) { <button type="submit" name="btn" value="verify"> Verify data</button> <button type="submit" name="btn" value="save"> Save data</button> <button type="submit" name="btn" value="redirect"> Redirect</button> } //controller public ActionResult About() { ViewBag.Message ="Your app description page."; return View(); } [HttpPost] public ActionResult About(input_element model) { if (model.Btn =="verify") { // the Verify button was clicked } else if (model.Btn =="save") { // the Save button was clicked } else if (model.Btn =="redirect") { // the Redirect button was clicked } return View(); } |
已修改的
属性类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class HttpParamActionAttribute : ActionNameSelectorAttribute { private readonly string actionName; public HttpParamActionAttribute(string actionName) { this.actionName = actionName; } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase)) return true; if (!actionName.Equals(this.actionName, StringComparison.InvariantCultureIgnoreCase)) return false; var request = controllerContext.RequestContext.HttpContext.Request; return request[methodInfo.Name] != null; } } |
控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [Authorize(Roles="CanAddContent")] public ActionResult CreateContent(Guid contentOwnerId) { var viewModel = new ContentViewModel { ContentOwnerId = contentOwnerId //populate rest of view model } return View("CreateContent", viewModel); } [Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken] public ActionResult SaveDraft(ContentFormModel model) { //Save as draft return RedirectToAction("CreateContent"); } [Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken] public ActionResult Publish(ContentFormModel model) { //publish content return RedirectToAction("CreateContent"); } |
视图
1 2 3 4 5 6 7 8 9 | @using (Ajax.BeginForm("CreateContent","MyController", new { contentOwnerId = Model.ContentOwnerId })) { @Html.AntiForgeryToken() @Html.HiddenFor(x => x.ContentOwnerId) <!-- Rest of your form controls --> <input name="SaveDraft" type="submit" value="SaveDraft" /> <input name="Publish" type="submit" value="Publish" /> } |
使用扩展方法的jquery方法:
1 2 3 4 5 6 7 8 9 | public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller { RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action); var onclick = string.Format("$('form').first().attr('action', '/{0}')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray())); var html ="<input type="submit" value="" + value +"" onclick="" + onclick +"" />"; return MvcHtmlString.Create(html); } |
您可以这样使用它:
1 | @(Html.SubmitButtonFor<FooController>(c => c.Save(null),"Save")) |
它呈现如下:
1 | <input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')"> |
对于每个提交按钮,只需添加:
1 2 3 4 5 6 | $('#btnSelector').click(function () { $('form').attr('action',"/Your/Action/); $('form').submit(); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | [HttpPost] public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model) { var button = nameValueResend ?? nameValueSubmit; if (button =="Resend") { } else { } } Razor file Content: @using (Html.BeginForm() { Confirm Mobile Number @Html.EditorFor(model => model.VefificationCode) @Html.LabelFor(model => model.VefificationCode, new { }) @Html.ValidationMessageFor(model => model.VefificationCode) <button type="submit" class="btn" name="nameValueResend" value="Resend"> Resend </button> <button type="submit" class="btn" name="nameValueSubmit" value="Verify"> Submit </button> } |
基于Mkozicki的回答,我提出了一个不同的解决方案。我仍然使用
属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class MultipleButtonActionAttribute : ActionNameSelectorAttribute { private readonly List<string> AcceptedButtonNames; public MultipleButtonActionAttribute(params string[] acceptedButtonNames) { AcceptedButtonNames = acceptedButtonNames.ToList(); } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { foreach (var acceptedButtonName in AcceptedButtonNames) { var button = controllerContext.Controller.ValueProvider.GetValue(acceptedButtonName); if (button == null) { continue; } controllerContext.Controller.ControllerContext.RouteData.Values.Add("ButtonName", acceptedButtonName); return true; } return false; } } |
看法
1 2 | <input type="submit" value="Save" name="Save" /> <input type="submit" value="Save and Sync" name="Sync" /> |
控制器
1 2 3 4 | [MultipleButtonAction("Save","Sync")] public ActionResult Sync(OrgSynchronizationEditModel model) { var btn = this.RouteData.Values["ButtonName"]; |
我还想指出,如果行动做了不同的事情,我可能会遵循mkozicki的帖子。
我为htmlhelper创建了一个actionButton方法。它将在onclick事件中生成带有一点javascript的普通输入按钮,将表单提交给指定的控制器/操作。
你用这样的助手
1 | @Html.ActionButton("MyControllerName","MyActionName","button text") |
这将生成以下HTML
1 | <input type="button" value="button text" onclick="this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();"> |
以下是扩展方法代码:
VB.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <System.Runtime.CompilerServices.Extension()> Function ActionButton(pHtml As HtmlHelper, pAction As String, pController As String, pRouteValues As Object, pBtnValue As String, pBtnName As String, pBtnID As String) As MvcHtmlString Dim urlHelperForActionLink As UrlHelper Dim btnTagBuilder As TagBuilder Dim actionLink As String Dim onClickEventJavascript As String urlHelperForActionLink = New UrlHelper(pHtml.ViewContext.RequestContext) If pController <>"" Then actionLink = urlHelperForActionLink.Action(pAction, pController, pRouteValues) Else actionLink = urlHelperForActionLink.Action(pAction, pRouteValues) End If onClickEventJavascript ="this.form.action = '" & actionLink &"'; this.form.submit();" btnTagBuilder = New TagBuilder("input") btnTagBuilder.MergeAttribute("type","button") btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript) If pBtnValue <>"" Then btnTagBuilder.MergeAttribute("value", pBtnValue) If pBtnName <>"" Then btnTagBuilder.MergeAttribute("name", pBtnName) If pBtnID <>"" Then btnTagBuilder.MergeAttribute("id", pBtnID) Return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal)) End Function |
C(C代码只是从vb dll中反编译的,所以它可以得到一些美化…但是时间太短了:(-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public static MvcHtmlString ActionButton(this HtmlHelper pHtml, string pAction, string pController, object pRouteValues, string pBtnValue, string pBtnName, string pBtnID) { UrlHelper urlHelperForActionLink = new UrlHelper(pHtml.ViewContext.RequestContext); bool flag = Operators.CompareString(pController,"", true) != 0; string actionLink; if (flag) { actionLink = urlHelperForActionLink.Action(pAction, pController, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues)); } else { actionLink = urlHelperForActionLink.Action(pAction, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues)); } string onClickEventJavascript ="this.form.action = '" + actionLink +"'; this.form.submit();"; TagBuilder btnTagBuilder = new TagBuilder("input"); btnTagBuilder.MergeAttribute("type","button"); btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript); flag = (Operators.CompareString(pBtnValue,"", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("value", pBtnValue); } flag = (Operators.CompareString(pBtnName,"", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("name", pBtnName); } flag = (Operators.CompareString(pBtnID,"", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("id", pBtnID); } return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal)); } |
这些方法有不同的参数,但是为了便于使用,您可以创建一些只接受所需参数的重载。
在使用Ajax表单时,我们可以将actionLinks与post-httpmethod和序列化AjaxOptions.OnBegin事件中的窗体。
假设您有两个操作,insertAction和updateAction:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <form> @Html.Hidden("SomeField","SomeValue") @Ajax.ActionLink( "Insert", "InsertAction", null, new AjaxOptions { OnBegin ="OnBegin", UpdateTargetId ="yourDiv", HttpMethod ="POST" }) @Ajax.ActionLink( "Update", "UpdateAction", null, new AjaxOptions { OnBegin ="OnBegin", UpdateTargetId ="yourDiv", HttpMethod ="POST" }) </form> |
JavaScript
1 2 3 | function OnBegin(xhr, settings) { settings.data = $("form").serialize(); } |
使用一个自定义助手(在项目根目录下的app_code文件夹中创建一个文件"helper s.cshtml")和javascript将表单的"action"属性重写(在"onclick"事件中),然后提交它。
帮助者可能是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @helper SubmitButton(string text, string controller,string action) { var uh = new System.Web.Mvc.UrlHelper(Context.Request.RequestContext); string url = @uh.Action(action, controller, null); <input type=button onclick="( function(e) { $(e).parent().attr('action', '@url'); //rewrite action url //create a submit button to be clicked and removed, so that onsubmit is triggered var form = document.getElementById($(e).parent().attr('id')); var button = form.ownerDocument.createElement('input'); button.style.display = 'none'; button.type = 'submit'; form.appendChild(button).click(); form.removeChild(button); } )(this)" value="@text"/> } |
然后将其用作:
1 2 3 | @Helpers.SubmitButton("Text for 1st button","ControllerForButton1","ActionForButton1") @Helpers.SubmitButton("Text for 2nd button","ControllerForButton2","ActionForButton2") ... |
在你的身体里。
在视图中,代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <script language="javascript" type="text/javascript"> function SubmeterForm(id) { if (id=='btnOk') document.forms[0].submit(id); else document.forms[1].submit(id); } <% Html.BeginForm("ObterNomeBotaoClicado/1","Teste01", FormMethod.Post); %> <input id="btnOk" type="button" value="Ok" onclick="javascript:SubmeterForm('btnOk')" /> <% Html.EndForm(); %> <% Html.BeginForm("ObterNomeBotaoClicado/2","Teste01", FormMethod.Post); %> <input id="btnCancelar" type="button" value="Cancelar" onclick="javascript:SubmeterForm('btnCancelar')" /> <% Html.EndForm(); %> |
在控制器中,代码为:
1 2 3 4 5 6 7 8 | public ActionResult ObterNomeBotaoClicado(string id) { if (id=="1") btnOkFunction(...); else btnCancelarFunction(...); return View(); } |
我的解决方案是使用2个ASP面板:
Index.cshtml
@using (Html.BeginForm("Index","Home", FormMethod.Post, new { id ="submitForm" }))
{
button type="submit" id="btnApprove" name="Command" value="Approve"> Approve
button type="submit" id="btnReject" name="Command" value="Reject"> Reject
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(FormCollection frm, string Command) { if (Command =="Approve") { } else if (Command =="Reject") { } return View(); } } |