如何在ASP中处理多个提交按钮。净MVC框架?

时间:2022-02-07 04:03:44

Is there some easy way to handle multiple submit buttons from the same form? 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中实现这一点吗?净框架β?我在google上搜索的所有例子都有一个按钮。

35 个解决方案

#1


542  

Here is a mostly clean attribute-based solution to the multiple submit button issue based heavily on the post and comments from Maartin Balliauw.

这是一个基于大量文章和Maartin 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 pages looks to provide the same functionality out of the box. For new development, it may be preferable.

更新:Razor页面看上去提供了开箱即用的相同功能。对于新开发,这可能是更好的选择。

#2


438  

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());
}

#3


115  

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方面(比如按钮名称),这是一个好主意。所以考虑使用两种形式和两种行动:

<% 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:

另外,在“Cancel”的情况下,您通常不会处理表单,而是要访问一个新的URL。在这种情况下,你根本不需要提交表格,只需要一个链接:

<%=Html.ActionLink("Cancel", "List", "MyController") %>

#4


92  

Eilon suggests you can do it like this:

埃隆建议你可以这样做:

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:

在控制器操作方法中,您可以添加以HTML输入标记名称命名的参数:

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.

如果有任何值被发送到其中一个参数,这意味着该按钮就是被单击的那个。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

See: http://forums.asp.net/p/1369617/2865166.aspx#2865166

见:http://forums.asp.net/p/1369617/2865166.aspx 2865166

#5


39  

Just written a post about that: Multiple submit buttons with ASP.NET MVC:

刚刚写了一篇关于这方面的文章:使用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.

如您所见,该属性并不要求您指定任何内容。同样,按钮的名称直接转换为方法名称。此外(我还没有尝试过),这些操作也可以正常工作,因此您可以直接将它们发布到任何一个操作中。

#6


34  

I would suggest interested parties have a look at Maarten Balliauw's solution. I think it is very elegant.

我建议有兴趣的各方看看马尔滕·巴利奥的解决方案。我认为它很优雅。

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属性来指示该动作应该与哪个按钮单击相关。

#7


22  

it is short and suite:

它是短套房,

It was answered by Jeroen Dop

耶罗波安回答

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />

and do like this in code behinde

后面的代码也是这样

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}

Good luck.

祝你好运。

#8


19  

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.

你应该能够给按钮命名并给它们一个值;然后将这个名称作为参数映射到动作。或者,使用两个单独的动作链接或两个表单。

#9


12  

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"...

然后在页面中检查name = "Send"或name = "Cancel"…

#10


11  

Something I don't like about ActionSelectName is that IsValidName is called for every action method in the controller; I don't know why it works this way. I like a solution where every button has a different name based on what it does, but I don't like the fact that you have to have as many parameters in the action method as buttons in the form. I have created an enum for all button types:

ActionSelectName中我不喜欢的一点是IsValidName用于控制器中的每个动作方法;我不知道为什么会这样。我喜欢的解决方案是,每个按钮都有不同的名称,这取决于它的功能,但我不喜欢在操作方法中必须有与表单中的按钮一样多的参数。我为所有按钮类型创建了一个enum:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Instead of ActionSelectName, I use an ActionFilter:

我使用ActionFilter代替ActionSelectName:

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;
            }
        }
    }
}

The filter will find the button name in the form data and if the button name matches any of the button types defined in the enum, it will find the ButtonType parameter among the action parameters:

过滤器将在表单数据中找到按钮名称,如果按钮名称与枚举中定义的任何按钮类型匹配,则在操作参数中找到按钮类型参数:

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}

and then in views, I can use:

在视图中,我可以使用:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />

#11


10  

Here is what works best for me:

以下是最适合我的方法:

<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();
}

#12


7  

If you do not have restrictions on the use of HTML 5, you can use the <button> tag with formaction Attribute:

如果您对使用HTML 5没有限制,可以使用带有formaction属性的

<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>

Reference: http://www.w3schools.com/html5/att_button_formaction.asp

参考:http://www.w3schools.com/html5/att_button_formaction.asp

#13


7  

I've came across this 'problem' as well but found a rather logical solution by adding the name attribute. I couldn't recall having this problem in other languages.

我也遇到过这个“问题”,但是通过添加name属性找到了一个相当合理的解决方案。我想不起来在其他语言中有这个问题。

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

http://www.w3.org/TR/html401/interact/forms.html h-17.13.2

  • ...
  • If a form contains more than one submit button, only the activated submit button is successful.
  • 如果表单包含多个submit按钮,则只有激活的submit按钮是成功的。
  • ...

Meaning the following code value attributes can be changed, localized, internationalized without the need for extra code checking strongly-typed resources files or constants.

这意味着可以更改以下代码值属性,本地化、国际化,不需要额外的代码检查强类型的资源文件或常量。

<% 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(); %>`

On the receiving end you would only need to check if any of your known submit types isn't null

在接收端,您只需要检查任何已知的提交类型是否为null

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

    }

}

#14


6  

David Findley writes about 3 different options you have for doing this, on his ASP.Net weblog.

David Findley在他的ASP上写了三种不同的选择。网络博客。

Read the article multiple buttons in the same form to 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.

阅读同一表单中的多个按钮以查看他的解决方案,以及每个按钮的优缺点。他提供了一个非常优雅的解决方案,利用你的行为装饰的属性。

#15


6  

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- multibuttones in The same-form.aspx)。它改编了迪伦·贝蒂的本地化解决方案,没有任何问题。

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;
         }
    }
}

#16


6  

This script allows to specify a data-form-action attribute which will work as the HTML5 formaction attribute in all browsers (in an unobtrusive way):

这个脚本允许指定一个data-form-action属性,它将作为HTML5 formaction属性在所有浏览器中工作(以一种不显眼的方式):

$(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);             
});

The form containing the button will be posted to the URL specified in the data-form-action attribute:

包含按钮的表单将被发送到data-form-action属性中指定的URL:

<button type="submit" data-form-action="different/url">Submit</button>   

This requires jQuery 1.7. For previous versions you should use live() instead of on().

这需要jQuery 1.7。对于以前的版本,应该使用live()而不是on()。

#17


6  

If your browser supports the attribute formaction for input buttons (IE 10+, not sure about other browsers) then the following should work:

如果您的浏览器支持输入按钮的属性formaction(即10+,不确定是否支持其他浏览器),那么以下内容应该可以工作:

@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") />

}

#18


6  

There are three ways by which you can solve the above issue

有三种方法可以解决上述问题。

  1. HTML way
  2. HTML的方式
  3. Jquery way
  4. Jquery的方式
  5. “ActionNameSelectorAttribute” way
  6. “ActionNameSelectorAttribute”的方式

Below is a video which summarizes all the three approaches in a demonstrative way.

下面是一个视频,用演示的方式总结了这三种方法。

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

HTML way :-

HTML的方式:

In the HTML way we need to create two forms and place the “Submit” button inside each of the forms. And every form’s action will point to different / respective actions. You can see the below code the first form is posting to “Action1” and the second form will post to “Action2” depending on which “Submit” button is clicked.

以HTML的方式,我们需要创建两个表单,并在每个表单中放置“Submit”按钮。每一种形式的动作都指向不同的动作。您可以看到下面的代码,第一个表单将发布到“Action1”,第二个表单将发布到“Action2”,这取决于单击哪个“提交”按钮。

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>

Ajax way :-

Ajax方式:-

In case you are a Ajax lover this second option would excite you more. In the Ajax way we can create two different functions “Fun1” and “Fun1” , see the below code. These functions will make Ajax calls by using JQUERY or any other framework. Each of these functions are binded with the “Submit” button’s “OnClick” events. Each of these function make call to respective action names.

如果您是Ajax爱好者,那么第二个选项将使您更感兴趣。使用Ajax,我们可以创建两个不同的函数“Fun1”和“Fun1”,请参见下面的代码。这些函数将使用JQUERY或任何其他框架进行Ajax调用。每个函数都与“提交”按钮的“OnClick”事件绑定在一起。每个函数都调用各自的操作名。

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<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>

Using “ActionNameSelectorAttribute”:-

使用“ActionNameSelectorAttribute”:-

This is a great and a clean option. The “ActionNameSelectorAttribute” is a simple attribute class where we can write decision making logic which will decide which action can be executed.

这是一个很好的选择。“ActionNameSelectorAttribute”是一个简单的属性类,我们可以在其中编写决策逻辑,该逻辑将决定可以执行哪些操作。

So the first thing is in HTML we need to put proper name’s to the submit buttons for identifying them on the server.

首先,在HTML中,我们需要在提交按钮上写上合适的名字,以便在服务器上识别它们。

You can see we have put “Save” and “Delete” to the button names. Also you can notice in the action we have just put controller name “Customer” and not a particular action name. We expect the action name will be decide by “ActionNameSelectorAttribute”.

您可以看到,我们已经将“保存”和“删除”放入按钮名称中。你也可以在动作中注意到,我们刚刚把控制器命名为“Customer”,而不是一个特定的动作名。我们希望动作名将由“ActionNameSelectorAttribute”决定。

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>

So when the submit button is clicked , it first hits the “ActionNameSelector” attribute and then depending on which submit is fired it invokes the appropriate action.

因此,当提交按钮被单击时,它首先会点击“ActionNameSelector”属性,然后根据哪个提交被触发,它会调用适当的操作。

如何在ASP中处理多个提交按钮。净MVC框架?

So the first step is to create a class which inherits from “ActionNameSelectorAttribute” class. In this class we have created a simple property “Name”.

所以第一步是创建一个继承自“ActionNameSelectorAttribute”类的类。在这个类中,我们创建了一个简单的属性“Name”。

We also need to override the “IsValidName” function which returns true or flase. This function is where we write the logic whether an action has to be executed or not. So if this function returns true then the action is executed or else it is not.

我们还需要重写“IsValidName”函数,该函数返回true或flase。这个函数是我们写入逻辑的地方,不管是否要执行操作。如果这个函数返回true那么这个动作就会被执行,否则它就不是。

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;

        }
    }

The main heart of the above function is in the below code. The “ValueProvider” collection has all the data that has been posted from the form. So it first looks up the “Name” value and if its found in the HTTP request it returns true or else it returns false.

上面函数的核心是下面的代码。“ValueProvider”集合包含从表单中发布的所有数据。所以它首先查找“Name”值,如果在HTTP请求中找到,它将返回true,否则返回false。

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;

This attribute class can then decorated on the respective action and the respective “Name” value can be provided. So if the submit is hitting this action and if the name matches of the HTML submit button name it then executes the action further or else it does not.

然后,可以在相应的操作上修饰这个属性类,并提供相应的“Name”值。因此,如果提交正在执行这个操作,并且如果HTML提交按钮名称的名称匹配,那么它将进一步执行该操作,否则就不会执行。

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}

#19


5  

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的表单参数(表示单击了一个图像按钮)并提取名称。对于常规的输入按钮,它会查找一个以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_。我喜欢这种方式,因为它意味着您可以更改文本(显示)值,而不必更改代码。与选择元素不同,输入按钮只有一个“值”,没有单独的“文本”属性。我的按钮在不同的环境下表达不同的东西——但是映射到相同的“命令”。我更喜欢用这种方式提取名称,而不是编写== = "Add to cart"。

#20


5  

I don't have enough rep to comment in the correct place, but I spent all day on this so want to share.

我没有足够的代表在正确的地方发表评论,但是我花了一整天的时间在这上面,所以我想分享。

While trying to implement the "MultipleButtonAttribute" solution ValueProvider.GetValue(keyValue) would incorrectly come back null.

当尝试实现“MultipleButtonAttribute”解决方案ValueProvider.GetValue(keyValue)时,会错误地返回null。

It turned out I was referencing System.Web.MVC version 3.0 when it should have been 4.0 (other assemblies are 4.0). I don't know why my project didn't upgrade correctly and I had no other obvious problems.

原来我是在引用System.Web。本应该是4.0的MVC版本(其他程序集是4.0)。我不知道为什么我的项目没有正确升级,也没有其他明显的问题。

So if your ActionNameSelectorAttribute is not working... check that.

如果你的ActionNameSelectorAttribute不工作…检查。

#21


4  

I've tried to make a synthesis of all solutions and created a [ButtenHandler] attribute that makes it easy to handle multiple buttons on a form.

我尝试对所有解决方案进行综合,并创建了一个[ButtenHandler]属性,该属性可以轻松处理表单上的多个按钮。

I've described it on CodeProject Multiple parameterized (localizable) form buttons in ASP.NET MVC.

我在代码项目中已经在ASP中描述了多个参数化(localizable)表单按钮。净MVC。

To handle the simple case of this button:

处理此按钮的简单情况:

<button type="submit" name="AddDepartment">Add Department</button>

You'll have something like the following action method:

你会得到如下的操作方法:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

Notice how the name of the button matches the name of the action method. The article also describes how to have buttons with values and buttons with indexes.

注意按钮的名称如何匹配操作方法的名称。本文还描述了如何使用带有值的按钮和带有索引的按钮。

#22


4  

//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();
        }

#23


4  

Modified version of HttpParamActionAttribute method but with a bug fix for not causing an error on expired/invalid session postbacks. To see if this is a problem with your current site, open the your form in a window and just before you go to click Save or Publish, open a duplicate window, and logout. Now go back to your first window and try to submit your form using either button. For me I got an error so this change solves that problem for me. I omit a bunch of stuff for the sake of brevity but you should get the idea. The key parts are the inclusion of ActionName on the attribute and making sure the name passed in is the name of the View that shows the form

修改后的HttpParamActionAttribute方法的版本,但是有一个bug修复,它不会导致过期/无效会话回发的错误。要查看当前站点是否存在此问题,请在窗口中打开窗体,在单击Save或Publish之前,打开一个复制窗口并注销。现在回到您的第一个窗口,尝试使用任一按钮提交表单。对我来说,我犯了一个错误,这个改变解决了我的问题。为了简洁起见,我省略了一些东西,但你们应该明白。关键部分是在属性上包含ActionName,并确保传入的名称是显示表单的视图的名称。

Attribute Class

属性类

[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;
    }
}

Controller

控制器

[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");
}

View

视图

@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" />
}

#24


4  

this is the best way that i have found:

这是我发现的最好的方法:

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

Here is the code:

这是代码:

    /// <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);
           }
       }
   }

Enjoy a code-smell-less multi submit button future.

享受一个没有代码的多提交按钮的未来。

thank you

谢谢你!

#25


4  

I'm pretty late to the party, but here goes... My implementation borrows from @mkozicki but requires less hardcoded strings to get wrong. Framework 4.5+ required. Essentially, the controller method name should be the key to the routing.

我很晚才来参加聚会,但是……我的实现借鉴了@mkozicki,但是需要更少的硬编码字符串来出错。需要框架4.5 +。实质上,控制器方法名应该是路由的关键。

Markup. The button name must be keyed with "action:[controllerMethodName]"

标记。按钮名必须键入“action:[controllerMethodName]”

(notice the use of the C#6 nameof API, providing type-specific reference to the name of the controller method you wish to invoke.

请注意使用c# 6 nameof API,为您希望调用的控制器方法的名称提供类型特定的引用。

<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>

Controller:

控制器:

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();
        }
    }
}

Attribute Magic. Notice the use of CallerMemberName goodness.

属性的魔法。注意CallerMemberName good的用法。

[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;
    }
}

#26


2  

My JQuery approach using an extension method:

我的JQuery方法使用扩展方法:

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);
}

You can use it like this:

你可以这样使用:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

And it renders like this:

它的渲染是这样的:

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >

#27


2  

For each submit button just add:

对于每个提交按钮,只需添加:

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});

#28


2  

Based on mkozicki answer I come up with a bit different solution. I still use ActionNameSelectorAttribute But I needed to handle two buttons 'Save' and 'Sync'. They do almost the same so I didn't want to have two actions.

基于mkozicki的回答,我提出了一个有点不同的解决方案。我仍然使用ActionNameSelectorAttribute,但是我需要处理两个按钮'Save'和'Sync'。它们几乎是一样的,所以我不想有两个动作。

attribute:

属性:

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;
    }
}

view

视图

<input type="submit" value="Save" name="Save" />
<input type="submit" value="Save and Sync" name="Sync" />

controller

控制器

 [MultipleButtonAction("Save", "Sync")]
 public ActionResult Sync(OrgSynchronizationEditModel model)
 {
     var btn = this.RouteData.Values["ButtonName"];

I also want to point out that if actions do different things I would probably follow mkozicki post.

我还想指出的是,如果行动做了不同的事情,我可能会追随mkozicki的帖子。

#29


1  

[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
    {
        var button = nameValueResend ?? nameValueSubmit;
        if (button == "Resend")
        {

        }
        else
        {

        }
    }


    Razor file Content:
    @using (Html.BeginForm()
    {
        <div class="page registration-result-page">

            <div class="page-title">
                <h1> Confirm Mobile Number</h1>
            </div>

            <div class="result">
                @Html.EditorFor(model => model.VefificationCode)
                @Html.LabelFor(model => model.VefificationCode, new { })
                @Html.ValidationMessageFor(model => model.VefificationCode)
            </div>
            <div class="buttons">
                <button type="submit" class="btn" name="nameValueResend" value="Resend">
                    Resend
                </button>
                <button type="submit" class="btn" name="nameValueSubmit" value="Verify">
                    Submit
                </button>

            </div>
            </div>

    }

#30


0  

When using ajax forms, we can use ActionLinks with POST HttpMethod and serialize the form in the AjaxOptions.OnBegin event.

在使用ajax表单时,我们可以使用带有POST HttpMethod的actionlink并在AjaxOptions中序列化表单。OnBegin事件。

Let's say you have two actions, InsertAction and UpdateAction:

假设您有两个操作,InsertAction和UpdateAction:

<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

Javascript

function OnBegin(xhr, settings) {
    settings.data = $("form").serialize();
}

#1


542  

Here is a mostly clean attribute-based solution to the multiple submit button issue based heavily on the post and comments from Maartin Balliauw.

这是一个基于大量文章和Maartin 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 pages looks to provide the same functionality out of the box. For new development, it may be preferable.

更新:Razor页面看上去提供了开箱即用的相同功能。对于新开发,这可能是更好的选择。

#2


438  

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());
}

#3


115  

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方面(比如按钮名称),这是一个好主意。所以考虑使用两种形式和两种行动:

<% 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:

另外,在“Cancel”的情况下,您通常不会处理表单,而是要访问一个新的URL。在这种情况下,你根本不需要提交表格,只需要一个链接:

<%=Html.ActionLink("Cancel", "List", "MyController") %>

#4


92  

Eilon suggests you can do it like this:

埃隆建议你可以这样做:

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:

在控制器操作方法中,您可以添加以HTML输入标记名称命名的参数:

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.

如果有任何值被发送到其中一个参数,这意味着该按钮就是被单击的那个。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

See: http://forums.asp.net/p/1369617/2865166.aspx#2865166

见:http://forums.asp.net/p/1369617/2865166.aspx 2865166

#5


39  

Just written a post about that: Multiple submit buttons with ASP.NET MVC:

刚刚写了一篇关于这方面的文章:使用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.

如您所见,该属性并不要求您指定任何内容。同样,按钮的名称直接转换为方法名称。此外(我还没有尝试过),这些操作也可以正常工作,因此您可以直接将它们发布到任何一个操作中。

#6


34  

I would suggest interested parties have a look at Maarten Balliauw's solution. I think it is very elegant.

我建议有兴趣的各方看看马尔滕·巴利奥的解决方案。我认为它很优雅。

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属性来指示该动作应该与哪个按钮单击相关。

#7


22  

it is short and suite:

它是短套房,

It was answered by Jeroen Dop

耶罗波安回答

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />

and do like this in code behinde

后面的代码也是这样

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}

Good luck.

祝你好运。

#8


19  

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.

你应该能够给按钮命名并给它们一个值;然后将这个名称作为参数映射到动作。或者,使用两个单独的动作链接或两个表单。

#9


12  

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"...

然后在页面中检查name = "Send"或name = "Cancel"…

#10


11  

Something I don't like about ActionSelectName is that IsValidName is called for every action method in the controller; I don't know why it works this way. I like a solution where every button has a different name based on what it does, but I don't like the fact that you have to have as many parameters in the action method as buttons in the form. I have created an enum for all button types:

ActionSelectName中我不喜欢的一点是IsValidName用于控制器中的每个动作方法;我不知道为什么会这样。我喜欢的解决方案是,每个按钮都有不同的名称,这取决于它的功能,但我不喜欢在操作方法中必须有与表单中的按钮一样多的参数。我为所有按钮类型创建了一个enum:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Instead of ActionSelectName, I use an ActionFilter:

我使用ActionFilter代替ActionSelectName:

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;
            }
        }
    }
}

The filter will find the button name in the form data and if the button name matches any of the button types defined in the enum, it will find the ButtonType parameter among the action parameters:

过滤器将在表单数据中找到按钮名称,如果按钮名称与枚举中定义的任何按钮类型匹配,则在操作参数中找到按钮类型参数:

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}

and then in views, I can use:

在视图中,我可以使用:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />

#11


10  

Here is what works best for me:

以下是最适合我的方法:

<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();
}

#12


7  

If you do not have restrictions on the use of HTML 5, you can use the <button> tag with formaction Attribute:

如果您对使用HTML 5没有限制,可以使用带有formaction属性的

<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>

Reference: http://www.w3schools.com/html5/att_button_formaction.asp

参考:http://www.w3schools.com/html5/att_button_formaction.asp

#13


7  

I've came across this 'problem' as well but found a rather logical solution by adding the name attribute. I couldn't recall having this problem in other languages.

我也遇到过这个“问题”,但是通过添加name属性找到了一个相当合理的解决方案。我想不起来在其他语言中有这个问题。

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

http://www.w3.org/TR/html401/interact/forms.html h-17.13.2

  • ...
  • If a form contains more than one submit button, only the activated submit button is successful.
  • 如果表单包含多个submit按钮,则只有激活的submit按钮是成功的。
  • ...

Meaning the following code value attributes can be changed, localized, internationalized without the need for extra code checking strongly-typed resources files or constants.

这意味着可以更改以下代码值属性,本地化、国际化,不需要额外的代码检查强类型的资源文件或常量。

<% 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(); %>`

On the receiving end you would only need to check if any of your known submit types isn't null

在接收端,您只需要检查任何已知的提交类型是否为null

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

    }

}

#14


6  

David Findley writes about 3 different options you have for doing this, on his ASP.Net weblog.

David Findley在他的ASP上写了三种不同的选择。网络博客。

Read the article multiple buttons in the same form to 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.

阅读同一表单中的多个按钮以查看他的解决方案,以及每个按钮的优缺点。他提供了一个非常优雅的解决方案,利用你的行为装饰的属性。

#15


6  

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- multibuttones in The same-form.aspx)。它改编了迪伦·贝蒂的本地化解决方案,没有任何问题。

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;
         }
    }
}

#16


6  

This script allows to specify a data-form-action attribute which will work as the HTML5 formaction attribute in all browsers (in an unobtrusive way):

这个脚本允许指定一个data-form-action属性,它将作为HTML5 formaction属性在所有浏览器中工作(以一种不显眼的方式):

$(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);             
});

The form containing the button will be posted to the URL specified in the data-form-action attribute:

包含按钮的表单将被发送到data-form-action属性中指定的URL:

<button type="submit" data-form-action="different/url">Submit</button>   

This requires jQuery 1.7. For previous versions you should use live() instead of on().

这需要jQuery 1.7。对于以前的版本,应该使用live()而不是on()。

#17


6  

If your browser supports the attribute formaction for input buttons (IE 10+, not sure about other browsers) then the following should work:

如果您的浏览器支持输入按钮的属性formaction(即10+,不确定是否支持其他浏览器),那么以下内容应该可以工作:

@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") />

}

#18


6  

There are three ways by which you can solve the above issue

有三种方法可以解决上述问题。

  1. HTML way
  2. HTML的方式
  3. Jquery way
  4. Jquery的方式
  5. “ActionNameSelectorAttribute” way
  6. “ActionNameSelectorAttribute”的方式

Below is a video which summarizes all the three approaches in a demonstrative way.

下面是一个视频,用演示的方式总结了这三种方法。

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

HTML way :-

HTML的方式:

In the HTML way we need to create two forms and place the “Submit” button inside each of the forms. And every form’s action will point to different / respective actions. You can see the below code the first form is posting to “Action1” and the second form will post to “Action2” depending on which “Submit” button is clicked.

以HTML的方式,我们需要创建两个表单,并在每个表单中放置“Submit”按钮。每一种形式的动作都指向不同的动作。您可以看到下面的代码,第一个表单将发布到“Action1”,第二个表单将发布到“Action2”,这取决于单击哪个“提交”按钮。

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>

Ajax way :-

Ajax方式:-

In case you are a Ajax lover this second option would excite you more. In the Ajax way we can create two different functions “Fun1” and “Fun1” , see the below code. These functions will make Ajax calls by using JQUERY or any other framework. Each of these functions are binded with the “Submit” button’s “OnClick” events. Each of these function make call to respective action names.

如果您是Ajax爱好者,那么第二个选项将使您更感兴趣。使用Ajax,我们可以创建两个不同的函数“Fun1”和“Fun1”,请参见下面的代码。这些函数将使用JQUERY或任何其他框架进行Ajax调用。每个函数都与“提交”按钮的“OnClick”事件绑定在一起。每个函数都调用各自的操作名。

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<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>

Using “ActionNameSelectorAttribute”:-

使用“ActionNameSelectorAttribute”:-

This is a great and a clean option. The “ActionNameSelectorAttribute” is a simple attribute class where we can write decision making logic which will decide which action can be executed.

这是一个很好的选择。“ActionNameSelectorAttribute”是一个简单的属性类,我们可以在其中编写决策逻辑,该逻辑将决定可以执行哪些操作。

So the first thing is in HTML we need to put proper name’s to the submit buttons for identifying them on the server.

首先,在HTML中,我们需要在提交按钮上写上合适的名字,以便在服务器上识别它们。

You can see we have put “Save” and “Delete” to the button names. Also you can notice in the action we have just put controller name “Customer” and not a particular action name. We expect the action name will be decide by “ActionNameSelectorAttribute”.

您可以看到,我们已经将“保存”和“删除”放入按钮名称中。你也可以在动作中注意到,我们刚刚把控制器命名为“Customer”,而不是一个特定的动作名。我们希望动作名将由“ActionNameSelectorAttribute”决定。

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>

So when the submit button is clicked , it first hits the “ActionNameSelector” attribute and then depending on which submit is fired it invokes the appropriate action.

因此,当提交按钮被单击时,它首先会点击“ActionNameSelector”属性,然后根据哪个提交被触发,它会调用适当的操作。

如何在ASP中处理多个提交按钮。净MVC框架?

So the first step is to create a class which inherits from “ActionNameSelectorAttribute” class. In this class we have created a simple property “Name”.

所以第一步是创建一个继承自“ActionNameSelectorAttribute”类的类。在这个类中,我们创建了一个简单的属性“Name”。

We also need to override the “IsValidName” function which returns true or flase. This function is where we write the logic whether an action has to be executed or not. So if this function returns true then the action is executed or else it is not.

我们还需要重写“IsValidName”函数,该函数返回true或flase。这个函数是我们写入逻辑的地方,不管是否要执行操作。如果这个函数返回true那么这个动作就会被执行,否则它就不是。

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;

        }
    }

The main heart of the above function is in the below code. The “ValueProvider” collection has all the data that has been posted from the form. So it first looks up the “Name” value and if its found in the HTTP request it returns true or else it returns false.

上面函数的核心是下面的代码。“ValueProvider”集合包含从表单中发布的所有数据。所以它首先查找“Name”值,如果在HTTP请求中找到,它将返回true,否则返回false。

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;

This attribute class can then decorated on the respective action and the respective “Name” value can be provided. So if the submit is hitting this action and if the name matches of the HTML submit button name it then executes the action further or else it does not.

然后,可以在相应的操作上修饰这个属性类,并提供相应的“Name”值。因此,如果提交正在执行这个操作,并且如果HTML提交按钮名称的名称匹配,那么它将进一步执行该操作,否则就不会执行。

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}

#19


5  

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的表单参数(表示单击了一个图像按钮)并提取名称。对于常规的输入按钮,它会查找一个以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_。我喜欢这种方式,因为它意味着您可以更改文本(显示)值,而不必更改代码。与选择元素不同,输入按钮只有一个“值”,没有单独的“文本”属性。我的按钮在不同的环境下表达不同的东西——但是映射到相同的“命令”。我更喜欢用这种方式提取名称,而不是编写== = "Add to cart"。

#20


5  

I don't have enough rep to comment in the correct place, but I spent all day on this so want to share.

我没有足够的代表在正确的地方发表评论,但是我花了一整天的时间在这上面,所以我想分享。

While trying to implement the "MultipleButtonAttribute" solution ValueProvider.GetValue(keyValue) would incorrectly come back null.

当尝试实现“MultipleButtonAttribute”解决方案ValueProvider.GetValue(keyValue)时,会错误地返回null。

It turned out I was referencing System.Web.MVC version 3.0 when it should have been 4.0 (other assemblies are 4.0). I don't know why my project didn't upgrade correctly and I had no other obvious problems.

原来我是在引用System.Web。本应该是4.0的MVC版本(其他程序集是4.0)。我不知道为什么我的项目没有正确升级,也没有其他明显的问题。

So if your ActionNameSelectorAttribute is not working... check that.

如果你的ActionNameSelectorAttribute不工作…检查。

#21


4  

I've tried to make a synthesis of all solutions and created a [ButtenHandler] attribute that makes it easy to handle multiple buttons on a form.

我尝试对所有解决方案进行综合,并创建了一个[ButtenHandler]属性,该属性可以轻松处理表单上的多个按钮。

I've described it on CodeProject Multiple parameterized (localizable) form buttons in ASP.NET MVC.

我在代码项目中已经在ASP中描述了多个参数化(localizable)表单按钮。净MVC。

To handle the simple case of this button:

处理此按钮的简单情况:

<button type="submit" name="AddDepartment">Add Department</button>

You'll have something like the following action method:

你会得到如下的操作方法:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

Notice how the name of the button matches the name of the action method. The article also describes how to have buttons with values and buttons with indexes.

注意按钮的名称如何匹配操作方法的名称。本文还描述了如何使用带有值的按钮和带有索引的按钮。

#22


4  

//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();
        }

#23


4  

Modified version of HttpParamActionAttribute method but with a bug fix for not causing an error on expired/invalid session postbacks. To see if this is a problem with your current site, open the your form in a window and just before you go to click Save or Publish, open a duplicate window, and logout. Now go back to your first window and try to submit your form using either button. For me I got an error so this change solves that problem for me. I omit a bunch of stuff for the sake of brevity but you should get the idea. The key parts are the inclusion of ActionName on the attribute and making sure the name passed in is the name of the View that shows the form

修改后的HttpParamActionAttribute方法的版本,但是有一个bug修复,它不会导致过期/无效会话回发的错误。要查看当前站点是否存在此问题,请在窗口中打开窗体,在单击Save或Publish之前,打开一个复制窗口并注销。现在回到您的第一个窗口,尝试使用任一按钮提交表单。对我来说,我犯了一个错误,这个改变解决了我的问题。为了简洁起见,我省略了一些东西,但你们应该明白。关键部分是在属性上包含ActionName,并确保传入的名称是显示表单的视图的名称。

Attribute Class

属性类

[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;
    }
}

Controller

控制器

[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");
}

View

视图

@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" />
}

#24


4  

this is the best way that i have found:

这是我发现的最好的方法:

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

Here is the code:

这是代码:

    /// <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);
           }
       }
   }

Enjoy a code-smell-less multi submit button future.

享受一个没有代码的多提交按钮的未来。

thank you

谢谢你!

#25


4  

I'm pretty late to the party, but here goes... My implementation borrows from @mkozicki but requires less hardcoded strings to get wrong. Framework 4.5+ required. Essentially, the controller method name should be the key to the routing.

我很晚才来参加聚会,但是……我的实现借鉴了@mkozicki,但是需要更少的硬编码字符串来出错。需要框架4.5 +。实质上,控制器方法名应该是路由的关键。

Markup. The button name must be keyed with "action:[controllerMethodName]"

标记。按钮名必须键入“action:[controllerMethodName]”

(notice the use of the C#6 nameof API, providing type-specific reference to the name of the controller method you wish to invoke.

请注意使用c# 6 nameof API,为您希望调用的控制器方法的名称提供类型特定的引用。

<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>

Controller:

控制器:

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();
        }
    }
}

Attribute Magic. Notice the use of CallerMemberName goodness.

属性的魔法。注意CallerMemberName good的用法。

[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;
    }
}

#26


2  

My JQuery approach using an extension method:

我的JQuery方法使用扩展方法:

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);
}

You can use it like this:

你可以这样使用:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

And it renders like this:

它的渲染是这样的:

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >

#27


2  

For each submit button just add:

对于每个提交按钮,只需添加:

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});

#28


2  

Based on mkozicki answer I come up with a bit different solution. I still use ActionNameSelectorAttribute But I needed to handle two buttons 'Save' and 'Sync'. They do almost the same so I didn't want to have two actions.

基于mkozicki的回答,我提出了一个有点不同的解决方案。我仍然使用ActionNameSelectorAttribute,但是我需要处理两个按钮'Save'和'Sync'。它们几乎是一样的,所以我不想有两个动作。

attribute:

属性:

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;
    }
}

view

视图

<input type="submit" value="Save" name="Save" />
<input type="submit" value="Save and Sync" name="Sync" />

controller

控制器

 [MultipleButtonAction("Save", "Sync")]
 public ActionResult Sync(OrgSynchronizationEditModel model)
 {
     var btn = this.RouteData.Values["ButtonName"];

I also want to point out that if actions do different things I would probably follow mkozicki post.

我还想指出的是,如果行动做了不同的事情,我可能会追随mkozicki的帖子。

#29


1  

[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
    {
        var button = nameValueResend ?? nameValueSubmit;
        if (button == "Resend")
        {

        }
        else
        {

        }
    }


    Razor file Content:
    @using (Html.BeginForm()
    {
        <div class="page registration-result-page">

            <div class="page-title">
                <h1> Confirm Mobile Number</h1>
            </div>

            <div class="result">
                @Html.EditorFor(model => model.VefificationCode)
                @Html.LabelFor(model => model.VefificationCode, new { })
                @Html.ValidationMessageFor(model => model.VefificationCode)
            </div>
            <div class="buttons">
                <button type="submit" class="btn" name="nameValueResend" value="Resend">
                    Resend
                </button>
                <button type="submit" class="btn" name="nameValueSubmit" value="Verify">
                    Submit
                </button>

            </div>
            </div>

    }

#30


0  

When using ajax forms, we can use ActionLinks with POST HttpMethod and serialize the form in the AjaxOptions.OnBegin event.

在使用ajax表单时,我们可以使用带有POST HttpMethod的actionlink并在AjaxOptions中序列化表单。OnBegin事件。

Let's say you have two actions, InsertAction and UpdateAction:

假设您有两个操作,InsertAction和UpdateAction:

<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

Javascript

function OnBegin(xhr, settings) {
    settings.data = $("form").serialize();
}