. 5> Andrey Shche..: 刚写了一篇关于它的帖子:
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")) { %>
<% } %>
和控制器有两种方法
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
如您所见,该属性不需要您指定任何内容.此外,按钮的名称将直接转换为方法名称.另外(我还没试过)这些也可以作为正常的动作,所以你可以直接发布到任何一个.
6> Izmoto..: 我建议有兴趣的人士看看Maarten Balliauw的解决方案.我觉得它非常优雅.
如果链接消失,它将使用MultiButton
应用于控制器操作的属性来指示该操作应该与哪个按钮单击相关联.
7> 小智..: 它很短且套房:
这是由Jeroen Dop回答的
并在代码behinde中这样做
if( Request.Form["submitbutton1"] != null)
{
// Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
// code for function 2
}
祝好运.
8> Marc Gravell..: 你应该能够命名按钮并给它们一个值; 然后将此名称映射为操作的参数.或者,使用2个单独的动作链接或2个表单.
9> Ironicnet..: 你可以写:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<% Html.EndForm(); %>
然后在页面中检查名称=="发送"或名称=="取消"...
10> sanjuro..: 关于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)
}
然后在视图中,我可以使用:
11> 小智..: 这对我最有用:
public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
if (onDelete != null)
{
// Delete the object
...
return EmptyResult();
}
// Save the object
...
return EmptyResult();
}
12> Acaz Souza..: 如果您对HTML 5的使用没有限制,则可以使用
带有formaction
属性的标记:
参考:http://www.w3schools.com/html5/att_button_formaction.asp
13> 小智..: 如果您的浏览器支持输入按钮的属性格式(IE 10+,不确定其他浏览器),则以下内容应该有效:
@using (Html.BeginForm()){
//put form inputs here
}
14> Tom Hofman..: 我也遇到过这个"问题",但通过添加name
属性找到了一个相当合理的解决方案.我记不起在其他语言中遇到这个问题了.
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
...
如果表单包含多个提交按钮,则只有激活的提交按钮成功.
...
这意味着value
可以更改,本地化,国际化以下代码属性,而无需 额外的代码检查强类型资源文件或常量.
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<% 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
}
}
15> Shivprasad K..: 您可以通过三种方式解决上述问题
HTML方式
Jquery的方式
"ActionNameSelectorAttribute"方式
以下是一个视频,以演示的方式总结了所有这三种方法.
https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940
HTML方式: -
在HTML方式中,我们需要创建两个表单,并在每个表单中放置"提交"按钮.每个表单的操作都将指向不同/相应的操作.您可以看到下面的代码,第一个表单发布到"Action1",第二个表单将发布到"Action2",具体取决于单击"提交"按钮.
Ajax方式: -
如果你是一个Ajax爱好者,这第二个选项会让你更兴奋.在Ajax方式中,我们可以创建两个不同的函数"Fun1"和"Fun1",请参阅下面的代码.这些函数将使用JQUERY或任何其他框架进行Ajax调用.这些功能中的每一个都与"提交"按钮的"OnClick"事件绑定在一起.这些函数中的每一个都调用各自的动作名称.
使用"ActionNameSelectorAttribute": -
这是一个伟大而干净的选择."ActionNameSelectorAttribute"是一个简单的属性类,我们可以编写决策逻辑,决定可以执行哪个操作.
所以第一件事就是HTML,我们需要在提交按钮上加上适当的名称,以便在服务器上识别它们.
您可以看到我们已将"保存"和"删除"添加到按钮名称中.您还可以注意到我们刚刚将控制器名称"Customer"而不是特定的操作名称放在操作中.我们希望操作名称由"ActionNameSelectorAttribute"决定.
因此,当单击提交按钮时,它首先点击"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;
然后可以在相应的动作上修饰该属性类,并且可以提供相应的"名称"值.因此,如果提交正在执行此操作,并且如果名称与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");
}
}
16> Saajid Ismai..: David Findley在他的ASP.Net博客上写了大约3种不同的选项.
阅读同一表格中的文章多个按钮,看看他的解决方案,以及每个按钮的优缺点.恕我直言,他提供了一个非常优雅的解决方案,利用你装饰你的行动的属性.
17> mlibby..: 这是我使用的技术,我还没有在这里看到它.启动此解决方案的链接(由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); %>
<%: Resources.Messages.Send %>
<%: Resources.Messages.Cancel %>
<% Html.EndForm(); %>
在控制器中:
public class MyController : Controller
{
public ActionResult MyAction(string button)
{
switch(button)
{
case "send":
this.DoSend();
break;
case "cancel":
this.DoCancel();
break;
}
}
}
18> Jay Douglass..: 此脚本允许指定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:
Submit
这需要jQuery 1.7.对于以前的版本,您应该使用live()
而不是on()
.
19> Simon_Weaver..: 这是我为处理多个图像和/或文本按钮而编写的扩展方法.
这是图像按钮的HTML:
或者用于文本提交按钮:
这是您从控制器调用的扩展方法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().Where(x => x.EndsWith(".x")).SingleOrDefault();
var textButton = formCollection.Keys.OfType().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"
.
20> 小智..: 我没有足够的代表在正确的地方发表评论,但我整天都花在这上面,所以想分享.
在尝试实现"MultipleButtonAttribute"解决方案时ValueProvider.GetValue(keyValue)
会错误地返回null
.
事实证明,当它应该是4.0(其他程序集是4.0)时,我引用的是System.Web.MVC 3.0版.我不知道为什么我的项目没有正确升级,我没有其他明显的问题.
所以如果你ActionNameSelectorAttribute
不工作......检查一下.
21> Aaron Hudon..: 我很晚才参加派对,但是这里......我的实现借鉴了@mkozicki,但需要较少的硬编码字符串才能出错. 需要框架4.5+ .实质上,控制器方法名称应该是路由的关键.
标记 .必须键入按钮名称"action:[controllerMethodName]"
(注意使用C#6 nameof API,提供特定于类型的引用,以指向您想要调用的控制器方法的名称.
控制器 :
namespace MyApp.Controllers
{
class MyController
{
[SubmitActionToThisMethod]
public async Task FundDeathStar(ImperialModel model)
{
await TrainStormTroopers();
return View();
}
[SubmitActionToThisMethod]
public async Task 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;
}
}
22> 小智..: 这是我找到的最佳方式:
http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html
这是代码:
///
/// ActionMethodSelector to enable submit buttons to execute specific action methods.
///
public class AcceptParameterAttribute : ActionMethodSelectorAttribute
{
///
/// Gets or sets the value to use to inject the index into
///
public string TargetArgument { get; set; }
///
/// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
///
public string Action { get; set; }
///
/// Gets or sets the regular expression to match the action.
///
public string ActionRegex { get; set; }
///
/// Determines whether the action method selection is valid for the specified controller context.
///
/// The controller context.
/// Information about the action method.
/// true if the action method selection is valid for the specified controller context; otherwise, false.
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
Func formGetter;
Func 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);
}
}
}
享受无需代码气味的多提交按钮未来.
谢谢
23> codetuner..: 我试图对所有解决方案进行综合,并创建了一个[ButtenHandler]属性,可以轻松处理表单上的多个按钮.
我在ASP.NET MVC中的 CodeProject 多参数化(可本地化)表单按钮上进行了描述.
要处理此按钮的简单情况:
Add Department
您将拥有类似以下操作方法的内容:
[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
model.Departments.Add(new Department());
return View(model);
}
请注意按钮的名称与操作方法的名称是否匹配.本文还介绍了如何使用带有索引的值和按钮的按钮.
24> SHAURAJ SING..: //model
public class input_element
{
public string Btn { get; set; }
}
//views--submit btn can be input type also...
@using (Html.BeginForm())
{
Verify data
Save data
Redirect
}
//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();
}
此外,您似乎发布只包含代码的答案,没有任何解释.您是否会考虑添加一些叙述来解释代码的工作原理,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何人来说非常有帮助. 当然,它工作正常.但很久以前,这个答案已经由其他人*给出了.他们还包括关于*为什么*它的工作原理的解释. 25> 小智..: [HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
{
var button = nameValueResend ?? nameValueSubmit;
if (button == "Resend")
{
}
else
{
}
}
Razor file Content:
@using (Html.BeginForm()
{
Confirm Mobile Number
@Html.EditorFor(model => model.VefificationCode)
@Html.LabelFor(model => model.VefificationCode, new { })
@Html.ValidationMessageFor(model => model.VefificationCode)
Resend
Submit
}