是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% 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框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
当前回答
我不喜欢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" />
其他回答
您可以像前面提到的那样检查动作中的名称,但是您可能会考虑这是否是好的设计。考虑动作的职责,不要将这种设计过多地与按钮名称等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") %>
基于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;
}
}
view
<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的帖子。
我建议感兴趣的人看看Maarten Balliauw的解决方案。我认为它非常优雅。
如果链接消失,它将使用应用于控制器操作的MultiButton属性来指示该操作应该与哪个按钮单击相关。
我也遇到过这个“问题”,但通过添加name属性找到了一个相当合理的解决方案。我不记得在其他语言中有这个问题。
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
... 如果表单包含多个提交按钮,则只有激活的提交按钮是成功的。 ...
这意味着以下代码值属性可以被更改、本地化、国际化,而不需要额外的代码检查强类型资源文件或常量。
<% 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(); %>`
在接收端,您只需要检查是否有任何已知的提交类型不是空
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
}
}
下面是基于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页面提供相同的功能开箱即用。对于新的开发来说,它可能更可取。