是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
当前回答
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
属性类
[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");
}
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" />
}
其他回答
你应该能够为按钮命名并赋予它们一个值;然后将此名称映射为操作的参数。或者,使用2个单独的动作链接或2个表单。
你可以这样写:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
然后在页面中检查name == "Send"或者name == "Cancel"…
下面是我写的一个扩展方法来处理多个图像和/或文本按钮。
下面是一个图片按钮的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的表单参数(表示单击了图像按钮)并提取名称。对于常规输入按钮,它查找以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按钮只有一个“value”,没有单独的“text”属性。我的按钮在不同的上下文中表示不同的内容-但映射到相同的“命令”。我更喜欢以这种方式提取名称,而不是必须为==“Add to cart”编码。
这是我使用的技巧,但我在这里还没有看到。链接(由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;
}
}
}
您可以像前面提到的那样检查动作中的名称,但是您可能会考虑这是否是好的设计。考虑动作的职责,不要将这种设计过多地与按钮名称等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") %>