C# 你如何处理 ASP.NET MVC 框架中的多个提交按钮?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/442704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you handle multiple submit buttons in ASP.NET MVC Framework?
提问by Spoike
Is there some easy way to handle multiple submit buttons from the same form? For example:
是否有一些简单的方法可以处理来自同一表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
Any idea how to do this in ASP.NET Framework Beta? All examples I've googled for have single buttons in them.
知道如何在 ASP.NET Framework Beta 中执行此操作吗?我用谷歌搜索过的所有示例中都有单个按钮。
采纳答案by mkozicki
Here is a mostly clean attribute-based solution to the multiple submit button issue based heavily on the post and comments from Maarten Balliauw.
这是一个基于属性的基于属性的解决方案,主要基于Maarten Balliauw的帖子和评论,用于解决多提交按钮问题。
[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;
}
}
razor:
剃刀:
<form action="" method="post">
<input type="submit" value="Save" name="action:Save" />
<input type="submit" value="Cancel" name="action:Cancel" />
</form>
and controller:
和控制器:
[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }
[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }
Update:Razor pageslooks to provide the same functionality out of the box. For new development, it may be preferable.
更新:Razor 页面看起来提供了开箱即用的相同功能。对于新的开发,它可能更可取。
回答by Marc Gravell
You should be able to name the buttons and give them a value; then map this name as an argument to the action. Alternatively, use 2 separate action-links or 2 forms.
你应该能够命名按钮并给它们一个值;然后将此名称作为参数映射到操作。或者,使用 2 个单独的操作链接或 2 个表单。
回答by Ironicnet
You could write:
你可以写:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
And then in the page check if the name == "Send" or name == "Cancel"...
然后在页面中检查名称==“发送”或名称==“取消”...
回答by Trevor de Koekkoek
You can check the name in the action as has been mentioned, but you might consider whether or not this is good design. It is a good idea to consider the responsibility of the action and not couple this design too much to UI aspects like button names. So consider using 2 forms and 2 actions:
您可以在前面提到的操作中检查名称,但您可能会考虑这是否是好的设计。考虑操作的责任并且不要将此设计过多地与按钮名称等 UI 方面结合是一个好主意。因此,请考虑使用 2 个表单和 2 个操作:
<% 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(); %>
Also, in the case of "Cancel", you are usually just not processing the form and are going to a new URL. In this case you do not need to submit the form at all and just need a link:
此外,在“取消”的情况下,您通常只是不处理表单,而是转到一个新的 URL。在这种情况下,您根本不需要提交表单,只需要一个链接:
<%=Html.ActionLink("Cancel", "List", "MyController") %>
回答by Dylan Beattie
Give your submit buttons a name, and then inspect the submitted value in your controller method:
为提交按钮命名,然后检查控制器方法中提交的值:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
posting to
发布到
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"));
}
}
EDIT:
编辑:
To extend this approach to work with localized sites, isolate your messages somewhere else (e.g. compiling a resource file to a strongly-typed resource class)
要扩展此方法以使用本地化站点,请将您的消息隔离在其他地方(例如,将资源文件编译为强类型资源类)
Then modify the code so it works like:
然后修改代码,使其工作方式如下:
<% 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(); %>
and your controller should look like this:
你的控制器应该是这样的:
// 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());
}
回答by PabloBlamirez
Eilon suggests you can do it like this:
Eilon 建议你可以这样做:
If you have more than one button you can distinguish between them by giving each button a name:
<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:
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 onebutton that got clicked. All other values will be null.
if (saveButton != null) { /* do save logic */ } if (cancelButton != null) { /* do cancel logic */ }
如果您有多个按钮,您可以通过为每个按钮命名来区分它们:
<input type="submit" name="SaveButton" value="Save data" /> <input type="submit" name="CancelButton" value="Cancel and go back to main page" />
在您的控制器操作方法中,您可以添加以 HTML 输入标签名称命名的参数:
public ActionResult DoSomeStuff(string saveButton, string cancelButton, ... other parameters ...) { ... }
如果任何值被发布到这些参数之一,这意味着该按钮是被点击的那个。Web 浏览器只会为被点击的一个按钮发布一个值。所有其他值都将为空。
if (saveButton != null) { /* do save logic */ } if (cancelButton != null) { /* do cancel logic */ }
I like this method as it does not rely on the value property of the submit buttons which is more likely to change than the assigned names and doesn't require javascript to be enabled
我喜欢这种方法,因为它不依赖于提交按钮的 value 属性,它比指定的名称更有可能改变,并且不需要启用 javascript
回答by Saajid Ismail
David Findley writes about 3 different options you have for doing this, on his ASP.Net weblog.
David Findley 在他的 ASP.Net 网络博客上写了大约 3 种不同的选择来执行此操作。
Read the article multiple buttons in the same formto see his solutions, and the advantages and disadvantages of each. IMHO he provides a very elegant solution which makes use of attributes that you decorate your action with.
阅读文章多个按钮相同的形式,看看他的解决方案,以及每个的优点和缺点。恕我直言,他提供了一个非常优雅的解决方案,它利用了你用来装饰你的动作的属性。
回答by Andrey Shchekin
Just written a post about that: Multiple submit buttons with ASP.NET MVC:
刚刚写了一篇关于这个的帖子: Multiple submit buttons with ASP.NET MVC:
Basically, instead of using ActionMethodSelectorAttribute
, I am using
ActionNameSelectorAttribute
, which allows me to pretend the action name is whatever I want it to be. Fortunately, ActionNameSelectorAttribute
does not just make me specify action name, instead I can choose whether the current action matches request.
基本上,ActionMethodSelectorAttribute
我使用的是,而不是使用
ActionNameSelectorAttribute
,这允许我假装动作名称是我想要的任何名称。幸运的是,ActionNameSelectorAttribute
不只是让我指定动作名称,而是我可以选择当前动作是否与请求匹配。
So there is my class (btw I am not too fond of the name):
所以有我的班级(顺便说一句,我不太喜欢这个名字):
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;
}
}
To use just define a form like this:
要使用,只需定义一个这样的表单:
<% using (Html.BeginForm("Action", "Post")) { %>
<!— …form fields… -->
<input type="submit" name="saveDraft" value="Save Draft" />
<input type="submit" name="publish" value="Publish" />
<% } %>
and controller with two methods
和控制器有两种方法
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
As you see, the attribute does not require you to specify anything at all. Also, name of the buttons are translated directly to the method names. Additionally (I haven't tried that) these should work as normal actions as well, so you can post to any of them directly.
如您所见,该属性根本不需要您指定任何内容。此外,按钮的名称直接转换为方法名称。此外(我还没有尝试过)这些也应该像正常操作一样工作,因此您可以直接发布到其中任何一个。
回答by Izmoto
I would suggest interested parties have a look at Maarten Balliauw's solution. I think it is very elegant.
我建议感兴趣的各方看看 Maarten Balliauw 的解决方案。我认为它非常优雅。
In case the link dissapears, it's using the MultiButton
attribute applied to a controller action to indicate which button click that action should relate to.
如果链接消失,它将使用MultiButton
应用于控制器操作的属性来指示该操作应与哪个按钮单击相关。
回答by mlibby
This is the technique I'd use and I don't see it here yet. The link (posted by Saajid Ismail ) that inspires this solution is http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx). It adapts Dylan Beattie's answer to do localization without any problems.
这是我将使用的技术,我还没有在这里看到它。激发此解决方案的链接(由 Saajid Ismail 发布)是http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form .aspx)。它改编了 Dylan Beattie 的答案,可以毫无问题地进行本地化。
In the View:
在视图中:
<% 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(); %>
In the Controller:
在控制器中:
public class MyController : Controller
{
public ActionResult MyAction(string button)
{
switch(button)
{
case "send":
this.DoSend();
break;
case "cancel":
this.DoCancel();
break;
}
}
}
回答by Simon_Weaver
Here's an extension method I wrote to handle multiple image and/or text buttons.
这是我编写的用于处理多个图像和/或文本按钮的扩展方法。
Here's the HTML for an image button:
这是图像按钮的 HTML:
<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png"
type="image">
or for a text submit button :
或文本提交按钮:
<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" />
Here is the extension method you call from the controller with form.GetSubmitButtonName()
. For image buttons it looks for a form parameter with .x
(which indicates an image button was clicked) and extracts the name. For regular input
buttons it looks for a name beginning with Submit_
and extracts the command from afterwards. Because I'm abstracting away the logic of determining the 'command' you can switch between image + text buttons on the client without changing the server side code.
这是您从控制器调用的扩展方法form.GetSubmitButtonName()
。对于图像按钮,它查找带有.x
(表示单击了图像按钮)的表单参数并提取名称。对于常规input
按钮,它会查找以 开头的名称Submit_
并从中提取命令。因为我抽象出了确定“命令”的逻辑,您可以在客户端上的图像 + 文本按钮之间切换,而无需更改服务器端代码。
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;
}
}
}
Note:For text buttons you have to prefix the name with Submit_
. I prefer this way becuase it means you can change the text (display) value without having to change the code. Unlike SELECT
elements, an INPUT
button has only a 'value' and no separate 'text' attribute. My buttons say different things under different contexts - but map to the same 'command'. I much prefer extracting the name this way than having to code for == "Add to cart"
.
注意:对于文本按钮,您必须在名称前加上Submit_
. 我更喜欢这种方式,因为这意味着您可以更改文本(显示)值而无需更改代码。与SELECT
元素不同,INPUT
按钮只有一个“值”而没有单独的“文本”属性。我的按钮在不同的上下文中说不同的东西 - 但映射到相同的“命令”。我更喜欢以这种方式提取名称而不是必须为== "Add to cart"
.