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

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

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


当前回答

我尝试综合所有的解决方案,并创建了一个[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);
}

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

其他回答

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

HTML的方式 Jquery的方式 “ActionNameSelectorAttribute”的方式

下面是一个视频,它以演示的方式总结了所有三种方法。

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

HTML方式:-

在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方式:-

如果您是Ajax爱好者,那么第二个选项会让您更兴奋。在Ajax中,我们可以创建两个不同的函数“Fun1”和“Fun1”,参见下面的代码。这些函数将使用JQUERY或任何其他框架进行Ajax调用。这些函数都与“Submit”按钮的“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”属性,然后根据触发的提交调用适当的操作。

因此,第一步是创建一个继承自“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;

然后可以在各自的操作上装饰这个属性类,并提供各自的“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");
        }
}

您可以像前面提到的那样检查动作中的名称,但是您可能会考虑这是否是好的设计。考虑动作的职责,不要将这种设计过多地与按钮名称等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(); %>

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

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

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

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

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

谢谢你!

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

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

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

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

我已经为HtmlHelper创建了一个ActionButton方法。它将在OnClick事件中生成带有javascript的普通输入按钮,将表单提交给指定的控制器/动作。

像这样使用辅助器

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

这将生成以下HTML

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

下面是扩展方法代码:

VB。网

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

这些方法具有各种参数,但是为了便于使用,您可以创建一些重载,只使用所需的参数。