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

时间:2009-01-14 11:58:36

标签: html asp.net asp.net-mvc http-post form-submit

是否有一些简单的方法可以处理来自同一表单的多个提交按钮?例如:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>

知道如何在ASP.NET Framework Beta中执行此操作吗?我用Google搜索的所有示例中都有单个按钮。

35 个答案:

答案 0 :(得分:593)

这是一个基于属性的解决方案,主要基于来自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;
    }
}

剃刀:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Cancel" name="action:Cancel" />
</form>

和控制器:

[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }

更新: Razor pages看起来提供开箱即用的相同功能。对于新的开发,可能更可取。

答案 1 :(得分:455)

为提交按钮指定名称,然后在控制器方法中检查提交的值:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>

张贴到

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

}

编辑:

要扩展此方法以使用本地化网站,请在其他位置隔离您的消息(例如,将资源文件编译为强类型资源类)

然后修改代码,使其工作方式如下:

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

并且您的控制器应如下所示:

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

答案 2 :(得分:119)

您可以检查操作中的名称,但是您可以考虑这是否是一个好的设计。考虑操作的责任并且不要将此设计与按钮名称等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(); %>

此外,在“取消”的情况下,您通常只是不处理表单并转到新的URL。在这种情况下,您根本不需要提交表单,只需要一个链接:

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

答案 3 :(得分:95)

Eilon建议你可以这样做:

  

如果您有多个按钮   可以通过给予来区分它们   每个按钮都有一个名字:

<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浏览器仅发布值   对于单击的 one 按钮。   所有其他值都将为空。

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }

我喜欢这种方法,因为它不依赖于提交按钮的value属性,它比指定的名称更有可能更改,并且不需要启用javascript

请参阅: http://forums.asp.net/p/1369617/2865166.aspx#2865166

答案 4 :(得分:43)

刚刚写了一篇关于此的帖子: Multiple submit buttons with ASP.NET MVC

基本上,我使用的不是ActionMethodSelectorAttribute ActionNameSelectorAttribute,它允许我假装动作名称是我想要的。幸运的是,ActionNameSelectorAttribute不只是让我指定操作名称,而是可以选择当前操作是否与请求匹配。

所以有我的课(顺便说一下,我不太喜欢这个名字):

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

使用只需定义这样的表单:

<% using (Html.BeginForm("Action", "Post")) { %>
  <!— …form fields… -->
  <input type="submit" name="saveDraft" value="Save Draft" />
  <input type="submit" name="publish" value="Publish" />
<% } %> 

和控制器有两种方法

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}

如您所见,该属性不需要您指定任何内容。此外,按钮的名称将直接转换为方法名称。另外(我还没试过)这些也可以作为正常的动作,所以你可以发布到任何一个 直接

答案 5 :(得分:35)

我建议感兴趣的各方have a look at Maarten Balliauw's solution。我认为这很优雅。

如果链接消失,则使用应用于控制器操作的MultiButton属性来指示该操作应该与哪个按钮相关。

答案 6 :(得分:31)

它很短且套房:

  

Jeroen Dop

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

并在代码behinde

中这样做
 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}
祝你好运。

答案 7 :(得分:21)

你应该可以命​​名按钮并给它们一个值;然后将此名称映射为操作的参数。或者,使用2个单独的动作链接或2个表单。

答案 8 :(得分:13)

你可以写:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

然后在页面中检查名称==“发送”或名称==“取消”......

答案 9 :(得分:12)

我对ActionSelectName不喜欢的是为控制器中的每个操作方法调用IsValidName;我不知道它为什么会这样。我喜欢一个解决方案,其中每个按钮根据它的作用有不同的名称,但我不喜欢你必须在动作方法中拥有与表单中的按钮一样多的参数。我为所有按钮类型创建了一个枚举:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

而不是ActionSelectName,我使用ActionFilter:

public class MultipleButtonsEnumAttribute : ActionFilterAttribute
{
    public Type EnumType { get; set; }

    public MultipleButtonsEnumAttribute(Type enumType)
    {
        EnumType = enumType;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach (var key in filterContext.HttpContext.Request.Form.AllKeys)
        {
            if (Enum.IsDefined(EnumType, key))
            {
                var pDesc = filterContext.ActionDescriptor.GetParameters()
                    .FirstOrDefault(x => x.ParameterType == EnumType);
                filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key);
                break;
            }
        }
    }
}

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

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

然后在视图中,我可以使用:

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

答案 10 :(得分:11)

这对我最有用:

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

答案 11 :(得分:9)

我遇到过这个问题&#39;同样,但通过添加name属性找到了一个相当合理的解决方案。我无法想起用其他语言解决这个问题。

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

  • ...
  • 如果表单包含多个提交按钮,则只有激活的提交按钮成功。
  • ...

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

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

在接收端,您只需要检查是否有任何已知的提交类型不是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

    }

}

答案 12 :(得分:9)

如果您的浏览器支持输入按钮的属性格式(IE 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") />

}

答案 13 :(得分:9)

如果您对HTML 5的使用没有限制,则可以将<button>标记与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>

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

答案 14 :(得分:8)

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

  1. HTML方式
  2. Jquery方式
  3. “ActionNameSelectorAttribute”方式
  4. 下面是一个视频,以演示的方式总结了所有这三种方法。

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

    HTML方式: -

    在HTML方式中,我们需要创建两个表单,并在每个表单中放置“提交”按钮。每个表单的操作都将指向不同/相应的操作。您可以看到下面的代码,第一个表单发布到“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方式: -

    如果您是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>
    

    使用“ActionNameSelectorAttribute”: -

    这是一个伟大而干净的选择。 “ActionNameSelectorAttribute”是一个简单的属性类,我们可以编写决策逻辑来决定可以执行的操作。

    所以第一件事就是HTML,我们需要在提交按钮上加上适当的名称,以便在服务器上识别它们。

    您可以看到我们已将“保存”和“删除”添加到按钮名称中。您还可以注意到我们刚刚将控制器名称“Customer”而不是特定的操作名称放在操作中。我们希望操作名称由“ActionNameSelectorAttribute”决定。

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

    因此,当单击提交按钮时,它首先命中“ActionNameSelector”属性,然后根据触发的提交,它会调用相应的操作。

    enter image description here

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

    我们还需要覆盖返回true或flase的“IsValidName”函数。这个函数是我们编写逻辑的地方,是否必须执行一个动作。因此,如果此函数返回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;
    
            }
        }
    

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

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

    然后可以在相应的动作上修饰该属性类,并且可以提供相应的“名称”值。因此,如果提交正在执行此操作,并且如果名称与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");
            }
    }
    

答案 15 :(得分:7)

此脚本允许指定data-form-action属性,该属性将作为所有浏览器中的HTML5格式属性(以不显眼的方式):

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

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

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

这需要jQuery 1.7。对于以前的版本,您应使用live()代替on()

答案 16 :(得分:7)

David Findley在他的ASP.Net博客上写了3个不同的选项。

阅读文章multiple buttons in the same form以查看他的解决方案,以及每种解决方案的优缺点。恕我直言,他提供了一个非常优雅的解决方案,利用你用你的行动装饰的属性。

答案 17 :(得分:7)

这是我使用的技术,我还没有在这里看到它。链接(由Saajid Ismail发布 )启发这个解决方案是http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx)。它使Dylan Beattie的答案适应本地化而没有任何问题。

在视图中:

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

在控制器中:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}

答案 18 :(得分:6)

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

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

事实证明,当它应该是4.0(其他程序集是4.0)时,我引用的是System.Web.MVC 3.0版。我不知道为什么我的项目没有正确升级,我没有其他明显的问题。

因此,如果您的ActionNameSelectorAttribute无效......请检查。

答案 19 :(得分:6)

我参加晚会很晚了,但是这里...... 我的实现借用了@mkozicki,但需要较少的硬编码字符串才能出错。 需要使用Framework 4.5+ 。实质上,控制器方法名称应该是路由的关键。

<强>标记即可。必须使用"action:[controllerMethodName]"

键入按钮名称

(注意使用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>

<强>控制器

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

属性魔法。请注意使用CallerMemberName善良。

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

答案 20 :(得分:6)

这是我为处理多个图像和/或文本按钮而编写的扩展方法。

以下是图片按钮的HTML:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">

或文字提交按钮:

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

以下是您使用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;
        }
    }
}

注意:对于文本按钮,您必须在名称前添加Submit_。我更喜欢这种方式,因为它意味着您可以更改文本(显示)值而无需更改代码。与SELECT元素不同,INPUT按钮只有“值”,没有单独的“文本”属性。我的按钮在不同的上下文中说不同的东西 - 但映射到相同的'命令'。我更喜欢以这种方式提取名称,而不是为== "Add to cart"编码。

答案 21 :(得分:5)

这是我找到的最佳方式:

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

以下是代码:

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

享受无需代码气味的多提交按钮。

谢谢

答案 22 :(得分:5)

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

我在CodeProject Multiple parameterized (localizable) form buttons in ASP.NET MVC上描述了它。

要处理此按钮的简单情况:

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

您将拥有类似以下操作方法的内容:

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

注意按钮的名称与操作方法的名称是否匹配。本文还介绍了如何使用包含值的按钮和带索引的按钮。

答案 23 :(得分:5)

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

答案 24 :(得分:4)

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

属性类

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

<强>控制器

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

查看

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

答案 25 :(得分:3)

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

    }

答案 26 :(得分:3)

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

你可以像这样使用它:

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

它呈现如下:

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

答案 27 :(得分:3)

根据mkozicki的回答,我提出了一个不同的解决方案。我仍然使用ActionNameSelectorAttribute但我需要处理两个按钮'保存'和'同步'。他们几乎一样,所以我不想有两个动作。

<强>属性

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

查看

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

<强>控制器

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

我还想指出,如果行动做不同的事情,我可能会关注mkozicki帖子。

答案 28 :(得分:3)

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

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

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

});

答案 29 :(得分:1)

我为 HtmlHelper 创建了 ActionButton 方法。它会在 OnClick事件中生成一些带有 javascript 的正常输入按钮,该按钮会将表单提交给指定的Controller / Action。

你使用那样的帮手

@Html.ActionButton("MyControllerName", "MyActionName", "button text")

这将生成以下HTML

<input type="button" value="button text" onclick="this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();">

这是扩展方法代码:

VB.Net

<System.Runtime.CompilerServices.Extension()>
Function ActionButton(pHtml As HtmlHelper, pAction As String, pController As String, pRouteValues As Object, pBtnValue As String, pBtnName As String, pBtnID As String) As MvcHtmlString
    Dim urlHelperForActionLink As UrlHelper
    Dim btnTagBuilder As TagBuilder

    Dim actionLink As String
    Dim onClickEventJavascript As String

    urlHelperForActionLink = New UrlHelper(pHtml.ViewContext.RequestContext)
    If pController <> "" Then
        actionLink = urlHelperForActionLink.Action(pAction, pController, pRouteValues)
    Else
        actionLink = urlHelperForActionLink.Action(pAction, pRouteValues)
    End If
    onClickEventJavascript = "this.form.action = '" & actionLink & "'; this.form.submit();"

    btnTagBuilder = New TagBuilder("input")
    btnTagBuilder.MergeAttribute("type", "button")

    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript)

    If pBtnValue <> "" Then btnTagBuilder.MergeAttribute("value", pBtnValue)
    If pBtnName <> "" Then btnTagBuilder.MergeAttribute("name", pBtnName)
    If pBtnID <> "" Then btnTagBuilder.MergeAttribute("id", pBtnID)

    Return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal))
End Function

C#(C#代码只是从VB DLL反编译,所以它可以得到一些美化......但时间太短了: - ))

public static MvcHtmlString ActionButton(this HtmlHelper pHtml, string pAction, string pController, object pRouteValues, string pBtnValue, string pBtnName, string pBtnID)
{
    UrlHelper urlHelperForActionLink = new UrlHelper(pHtml.ViewContext.RequestContext);
    bool flag = Operators.CompareString(pController, "", true) != 0;
    string actionLink;
    if (flag)
    {
        actionLink = urlHelperForActionLink.Action(pAction, pController, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    else
    {
        actionLink = urlHelperForActionLink.Action(pAction, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    string onClickEventJavascript = "this.form.action = '" + actionLink + "'; this.form.submit();";
    TagBuilder btnTagBuilder = new TagBuilder("input");
    btnTagBuilder.MergeAttribute("type", "button");
    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript);
    flag = (Operators.CompareString(pBtnValue, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("value", pBtnValue);
    }
    flag = (Operators.CompareString(pBtnName, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("name", pBtnName);
    }
    flag = (Operators.CompareString(pBtnID, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("id", pBtnID);
    }
    return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal));
}

这些方法有各种参数,但为了方便使用,你可以创建一些只需要你需要的参数的重载。

答案 30 :(得分:0)

使用ajax表单时,我们可以将ActionLinks与POST HttpMethod一起使用 序列化AjaxOptions.OnBegin事件中的表单。

假设您有两个操作,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

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

答案 31 :(得分:0)

使用自定义帮助程序(在项目根目录下的App_Code文件夹中创建文件“Helpers.cshtml”),使用javascript将表单的“action”属性重写(在'onclick'事件中)为您想要的内容然后提交。

助手可能像:

@helper SubmitButton(string text, string controller,string action)
{   
    var uh = new System.Web.Mvc.UrlHelper(Context.Request.RequestContext);
    string url = @uh.Action(action, controller, null);   
    <input type=button  onclick="(
                                       function(e)
                                                 {
                                                   $(e).parent().attr('action', '@url'); //rewrite action url
                                                   //create a submit button to be clicked and removed, so that onsubmit is triggered
                                                   var form = document.getElementById($(e).parent().attr('id'));
                                                   var button = form.ownerDocument.createElement('input');
                                                   button.style.display = 'none';
                                                   button.type = 'submit';
                                                   form.appendChild(button).click(); 
                                                   form.removeChild(button);              
                                                  }
                                      )(this)" value="@text"/>
}

然后将其用作:

@Helpers.SubmitButton("Text for 1st button","ControllerForButton1","ActionForButton1")
@Helpers.SubmitButton("Text for 2nd button","ControllerForButton2","ActionForButton2")
...

在表单中。

答案 32 :(得分:-1)

在View中,代码是:

<script language="javascript" type="text/javascript">
    function SubmeterForm(id)
    {
        if (id=='btnOk')
            document.forms[0].submit(id);
        else
            document.forms[1].submit(id);
    }
</script>


<% Html.BeginForm("ObterNomeBotaoClicado/1", "Teste01", FormMethod.Post); %>
<input id="btnOk" type="button" value="Ok" onclick="javascript:SubmeterForm('btnOk')" />
<% Html.EndForm(); %>
<% Html.BeginForm("ObterNomeBotaoClicado/2", "Teste01", FormMethod.Post); %>
<input id="btnCancelar" type="button" value="Cancelar" onclick="javascript:SubmeterForm('btnCancelar')" />
<% Html.EndForm(); %>

在Controller中代码为:

public ActionResult ObterNomeBotaoClicado(string id)
{
    if (id=="1")
        btnOkFunction(...);
    else
        btnCancelarFunction(...);
    return View();
}

答案 33 :(得分:-2)

我的解决方案是使用2个asp面板:

<asp:Panel ID=”..” DefaultButton=”ID_OF_SHIPPING_SUBMIT_BUTTON”….></asp:Panel>

答案 34 :(得分:-3)

  

Index.cshtml

     

@using(Html.BeginForm(&#34; Index&#34;,&#34; Home&#34;,FormMethod.Post,new {id =&#34; submitForm&#34;}))

     

{

     

按钮类型=&#34;提交&#34; ID =&#34; btnApprove&#34;名称=&#34;命令&#34;值=&#34;批准&#34;&GT;批准

     

按钮类型=&#34;提交&#34; ID =&#34; btnReject&#34;名称=&#34;命令&#34;值=&#34;拒绝&#34;&GT;拒绝

     

}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(FormCollection frm, string Command)
    {
        if (Command == "Approve")
        {

        }
        else if (Command == "Reject")
        {

        }

        return View();
    }

}