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

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

知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。


当前回答

我的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')" >

其他回答

下面是基于Maarten Balliauw的帖子和评论,针对多个提交按钮问题的一个非常干净的基于属性的解决方案。

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

剃须刀:

<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页面提供相同的功能开箱即用。对于新的开发来说,它可能更可取。

视图中的代码是:

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

我尝试综合所有的解决方案,并创建了一个[ButtenHandler]属性,它可以很容易地处理表单上的多个按钮。

我已经在CodeProject中描述了它在ASP中的多个参数化(本地化)表单按钮。净MVC。

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

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

你会有如下的动作方法:

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

注意按钮的名称与动作方法的名称是如何匹配的。本文还描述了如何让按钮具有值和按钮具有索引。

我建议感兴趣的人看看Maarten Balliauw的解决方案。我认为它非常优雅。

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

刚刚写了一篇相关的文章: 多个提交按钮与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(…) {
        //…
    } 
}

如您所见,该属性根本不需要指定任何内容。此外,按钮的名称直接转换为方法名称。此外(我还没有尝试过)这些应该作为正常的动作以及,所以你可以张贴到他们中的任何一个 直接。