Есть ли простой способ обрабатывать несколько кнопок отправки из одной формы? Например:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type = "submit" value = "Send" />
<input type = "submit" value = "Cancel" />
<% Html.EndForm(); %>
Есть идеи, как это сделать в бета-версии ASP.NET Framework? Во всех примерах, которые я искал в Google, есть отдельные кнопки.
Этот учебник может помочь: Отправка формы в различные методы действий в ASP.NET MVC





Вы должны иметь возможность давать кнопкам имена и значения; затем сопоставьте это имя как аргумент действия. В качестве альтернативы используйте 2 отдельные ссылки действия или 2 формы.
Безусловно, самое чистое и простое решение, которое я когда-либо видел.
Вы могли написать:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type = "submit" name = "button" value = "Send" />
<input type = "submit" name = "button" value = "Cancel" />
<% Html.EndForm(); %>
А затем на странице проверьте, есть ли имя == «Отправить» или имя == «Отменить» ...
Хотя это работает, но я считаю неправильной практикой иметь два элемента с одинаковыми именами.
Это не обязательно неправильно. Это зависит от того, как вы используете входы. У вас может быть несколько элементов с одинаковым именем и ожидание получения нескольких данных (так работают радиокнопки и флажки). Но да, если вы используете этот метод, это потому, что вы делаете это «неправильно» ... Вот почему я поставил «Вы могли бы», но не «Вы должны»: P
Вы можете проверить имя в действии, как уже упоминалось, но вы можете подумать, хороший ли это дизайн. Хорошая идея - учитывать ответственность за действие и не связывать этот дизайн слишком сильно с такими аспектами пользовательского интерфейса, как названия кнопок. Поэтому рассмотрите возможность использования 2 форм и 2 действий:
<% 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") %>
Это нормально, если вам не нужны одни и те же данные формы для каждой кнопки отправки. Если вам нужны все данные в единой форме, то вам подойдет Дилан Битти. Есть ли более элегантный способ сделать это?
Насчет визуального представления, как в этом случае кнопка «Отправить» рядом с кнопкой «Отменить»?
Дилан: Что ж, для кнопки отмены вам вообще не нужно отправлять данные, и связывать контроллер с элементами пользовательского интерфейса - плохая практика. Однако, если вы можете создать более или менее общую «команду», я думаю, что это нормально, но я бы не привязывал ее к «submitButton», поскольку это имя элемента пользовательского интерфейса.
@Kris: вы можете размещать свои кнопки с помощью CSS, и они по-прежнему могут находиться в двух разных разделах формы.
Я думаю, здесь следует упомянуть, что если класс контроллера называется MyController, второй параметр должен читать не MyController, а просто My, поскольку предполагается, что часть имени контролер.
шутки в сторону? это не пахнет никому, кроме меня ?!
Я не могу понять, почему это было выбрано как правильный ответ. HTML5 поддерживает formaction для отправки формы по разным URL-адресам, поэтому я подозреваю, что это не такая уж плохая идея ...
По сути, это ответ на актуальный вопрос. И всего этого можно добиться, просто используя значения маршрута. Пока он не публикует никаких фактических данных. Так что я собираюсь проголосовать за это.
Дайте вашим кнопкам отправки имя, а затем проверьте отправленное значение в методе вашего контроллера:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type = "submit" name = "submitButton" value = "Send" />
<input type = "submit" name = "submitButton" value = "Cancel" />
<% Html.EndForm(); %>
размещение в
public class MyController : Controller {
public ActionResult MyAction(string submitButton) {
switch(submitButton) {
case "Send":
// delegate sending to another controller action
return(Send());
case "Cancel":
// call another action to perform the cancellation
return(Cancel());
default:
// If they've submitted the form without a submitButton,
// just return the view again.
return(View());
}
}
private ActionResult Cancel() {
// process the cancellation request here.
return(View("Cancelled"));
}
private ActionResult Send() {
// perform the actual send operation here.
return(View("SendConfirmed"));
}
}
Обновлено:
Чтобы расширить этот подход для работы с локализованными сайтами, изолируйте свои сообщения в другом месте (например, скомпилируйте файл ресурсов в строго типизированный класс ресурсов)
Затем измените код, чтобы он работал так:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type = "submit" name = "submitButton" value = "<%= Html.Encode(Resources.Messages.Send)%>" />
<input type = "submit" name = "submitButton" value = "<%=Html.Encode(Resources.Messages.Cancel)%>" />
<% Html.EndForm(); %>
и ваш контроллер должен выглядеть так:
// Note that the localized resources aren't constants, so
// we can't use a switch statement.
if (submitButton == Resources.Messages.Send) {
// delegate sending to another controller action
return(Send());
} else if (submitButton == Resources.Messages.Cancel) {
// call another action to perform the cancellation
return(Cancel());
}
Это то, что я здесь искал: stackoverflow.com/questions/649513/… - спасибо
жаль, что вы зависите от текста, отображаемого на кнопке, это довольно сложно с многоязычным пользовательским интерфейсом
Ому - см. Последнее изменение, в котором объясняется (вкратце!), Как сделать то же самое с локализованными ресурсами строк / сообщений.
Переключатель / регистр работает только с константами, поэтому в локализованной версии нельзя использовать переключатель / регистр. Вам нужно переключиться на if else или другой метод отправки.
Взгляните на решение от Izmoto с использованием атрибута MultiButton, оно кажется очень хорошим.
@mcl - ты абсолютно прав. Код был отредактирован для использования if / else вместо switch () для локализованной версии. Спасибо.
А как насчет проверки формы? Некоторые кнопки могут не требовать полной проверки формы.
@DylanBeattie, что, если представление состоит из частичных представлений, и вы хотите проверить представление? Означает, что каждая кнопка отправки будет соответствовать другому представлению, и связанное действие должно сначала подтвердить представление. Главное действие проверит все частичные представления перед продолжением.
@DylanBeattie: Что, если я хочу передать модель в качестве параметра моему методу действия? Могу ли я получить название кнопки в этом случае?
@Biki - да, просто привяжите значение кнопки в качестве параметра вашей модели. В нескольких местах я разделил конкретную модель на явные ViewModel и PostModel - затем вы вызываете кнопку отправки примерно так: <input type = "submit" name = "model.SubmitButton" value = "Yada" />, а затем передать (модель PostModel) в метод вашего контроллера, и вы должны обнаружить, что значение кнопки доступно в model.SubmitButton.
вам следует использовать <button type = "submit" вместо <input type, потому что значение типа кнопки <не является текстом;). Тогда у вас может получиться что-то вроде этого: <button name = "mySubmitButton" type = "submit" value = "keyValue"> YourButtonText </button>
@iwayneo, интересное решение. Когда я зашел туда, сайт не работал, но на обратном пути он был: web.archive.org/web/20110312212221/http://blogs.sonatribe.co м /…
А как насчет захвата всей модели в контроллере в дополнение к кнопке отправки (строка submitButton)?
Как это будет работать с передачей модели в действие, а не просто значение отправки?
см. также stackoverflow.com/questions/4171664/…, чтобы узнать, как создать кнопку, текст которой может отличаться от представленного значения
Будьте осторожны и не называйте кнопки «действием», если вы используете jQuery. Это вызывает конфликт в библиотеке, который нарушает URL-адрес действия.
Чтобы ответить от @bizzehdee, просто передайте модель в качестве первого параметра и имя кнопки отправки в качестве второго параметра.
Этот подход намного проще, чем безумные штучки с настраиваемыми атрибутами. Принцип KISS для победы.
-1, на практике я вижу, что такой подход приводит к ужасному коду. Во-первых, вам становится трудно следовать логике, а во-вторых, вам приходится принимать все параметры, необходимые для каждого конкретного метода, что приводит к массовому объявлению метода. Подход с настраиваемыми атрибутами - это подход KISS! Если вам не нравятся настраиваемые атрибуты, ASP.NET не для вас ...
@DylanBeattie Есть ли хороший способ передать идентификатор (кнопка удаления с идентификатором)?
Эйлон предлагает сделать это так:
If you have more than one button you can distinguish between them by giving each button a name:
<input type = "submit" name = "SaveButton" value = "Save data" /> <input type = "submit" name = "CancelButton" value = "Cancel and go back to main page" />In your controller action method you can add parameters named after the HTML input tag names:
public ActionResult DoSomeStuff(string saveButton, string cancelButton, ... other parameters ...) { ... }If any value gets posted to one of those parameters, that means that button was the one that got clicked. The web browser will only post a value for the one button that got clicked. All other values will be null.
if (saveButton != null) { /* do save logic */ } if (cancelButton != null) { /* do cancel logic */ }
Мне нравится этот метод, поскольку он не полагается на свойство value кнопок отправки, которое с большей вероятностью изменится, чем назначенные имена, и не требует включения javascript.
Видеть: http://forums.asp.net/p/1369617/2865166.aspx#2865166
Если кто-то столкнется с этим старым вопросом, это самый ясный ответ, если вы не хотите использовать элементы HTML5 <button>. Если вы не против HTML5, используйте <button> с атрибутом value.
Как бы вы это сделали, если бы создавали в этой форме вызов ajax. Кажется, что form.serialize () не подбирает имя кнопки отправки ..
@Kugel прав, это все еще самый чистый ответ. Спасибо
Дэвид Финдли в своем блоге ASP.Net пишет о трех различных вариантах, которые у вас есть.
Прочтите статью несколько кнопок в одной форме, чтобы увидеть его решения, а также преимущества и недостатки каждого из них. ИМХО, он предлагает очень элегантное решение, в котором используются атрибуты, которыми вы украшаете свое действие.
Только что написал об этом пост: Несколько кнопок отправки с 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(…) {
//…
}
}
Как видите, атрибут не требует от вас вообще ничего указывать. Кроме того, названия кнопок транслируются непосредственно в названия методов. Кроме того (я этого не пробовал), они также должны работать как обычные действия, поэтому вы можете публиковать сообщения в любом из них. напрямую.
Красивый! Я считаю это наиболее элегантным решением. Это исключает из рассмотрения значение тега submit, что идеально, поскольку это атрибут чистого пользовательского интерфейса, который не должен иметь никакого отношения к потоку управления. Вместо этого уникальный атрибут name каждого тега submit транслируется непосредственно в дискретный метод действия на вашем контроллере.
+1 Для меня это однозначно лучшее решение этой проблемы. Поскольку я реализовал это, я заметил, что через HttpParamActionAttribut проходит много трафика, но по сравнению со всеми другими вещами, которые Asp.Net MVC должен делать при обработке запроса, это вполне приемлемо. Чтобы взломать только то, что мне нужно сделать, это поместить пустое «Действие» с именем в моем контроллере, чтобы Resharper не предупреждал меня о том, что действие «Действие» не существует. Большое спасибо!
Я просмотрел все решения и согласен, что это красивое, элегантное и простое решение. Отлично, что нет условных операторов и надежных, где вы можете определить новое действие контроллера, когда у вас есть новая кнопка. Называется мой класс MultiButtonActionHandler FYI ;-)
Предлагаю заинтересованным сторонам взгляните на решение Maarten Balliauw. Я считаю, что это очень элегантно.
В случае, если ссылка пропадает, он использует атрибут MultiButton, примененный к действию контроллера, чтобы указать, к какому нажатию кнопки должно относиться это действие.
Это решение, которое мы используем сейчас, и оно очень удобное. Это только MVC 2?
Это прекрасно! Я такого раньше не видел! Хотя я согласен с тем, что вы можете захотеть переделать любое решение, использующее несколько отправок, чтобы использовать только одну кнопку, я нахожусь в затруднительном положении и должен это сделать. Этот ответ должен был победить!
Это отличное решение. Очень чистый
Пробовал этот подход и не смог заставить его работать в MVC3. У меня сработал вариант получателя голосов №1.
Коротко и мило .. но не для mvc 3+
Это еще один полезный ссылка на сайт, объясняющий различные способы создания сообщений.
Я бы использовал эту технику, но я ее здесь пока не вижу. Ссылка (опубликована Сааджидом Исмаилом ), который вдохновляет на это решение, является http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx). Он адаптирует ответ Дилана Битти, чтобы без проблем выполнить локализацию.
В представлении:
<% 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;
}
}
}
Похоже, решение Ироникнет предоставил.
Конечно, похоже, но здесь показаны как локализация, так и код контроллера, чего я не видел в этом потоке. Я нашел эту ветку, когда искал, как это сделать, и хотел задокументировать то, что я придумал, для всех, кто может оказаться в той же лодке.
На самом деле, это не то же самое, что и Ironicnet, кроме этого. Он использует элементы <input>. Я использую <button>, который требуется для локализации без атрибутов значений переменных.
Вот метод расширения, который я написал для обработки нескольких кнопок с изображениями и / или текстом.
Вот 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 (который указывает, что была нажата кнопка изображения) и извлекает имя. Для обычных кнопок 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<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 имеет только «значение» и не имеет отдельного атрибута «текст». Мои кнопки говорят разные вещи в разных контекстах, но соответствуют одной и той же «команде». Я предпочитаю извлекать имя таким образом, чем кодировать == "Add to cart".
Мне нравится проверять имя в качестве альтернативы, потому что вы не всегда можете проверить значение, например. у вас есть список элементов, и у каждого есть кнопка «Удалить».
В представлении код:
<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(); %>
В контроллере код:
public ActionResult ObterNomeBotaoClicado(string id)
{
if (id= = "1")
btnOkFunction(...);
else
btnCancelarFunction(...);
return View();
}
В будущем вам будет полезно объяснять свой код. Спасибо!
Вот в основном чистое решение проблемы с несколькими кнопками отправки на основе атрибутов, в значительной степени основанное на публикации и комментариях от 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 Pages, похоже, обеспечивает ту же функциональность из коробки. Для новых разработок это может быть предпочтительнее.
Я нашел это решение счастливым браком с другими используемыми техниками. Отлично работает и не влияет на локализацию.
Отличное решение !! Гораздо полезнее, чем эти самые популярные ответы
что такое строка 'value = new ValueProviderResult (Argument, Argument, null);' используется для? Это кажется лишним.
Я пытаюсь реализовать это, но это не работает. Похоже, что атрибут никогда не попадает. Он идет прямо в мой контроллер индекса. Есть идеи, почему?
@AdeLia У меня не было проблем с просто декорированием методов атрибутом MultipleSubmit. Я рад помочь, но для этого мне нужна дополнительная информация (код, разметка и т. д.).
@mkozicki Похоже, это произошло потому, что у меня был класс MultipleButtonAttribute в другом проекте. Как только я помещаю его в тот же проект, он работает. Странно, я бы не подумал, что это будет проблемой, если ссылка верна.
Мне нравится, мило и чисто, мне придется добавить это в свой набор инструментов
Дааааааааа. Работает на MVC 4.5. Другой, похоже, не работает. отлично +1
Проблема с этим подходом заключается в том, что если вы попытаетесь выполнить return View(viewmodel) в случае, когда ваша модель имеет ошибки, она попытается вернуть представление с именем Send или в зависимости от имени вашего аргумента.
@Shoe - только что нашел похожую вещь. Убедитесь, что вы явно указали имя представления, которое нужно вернуть, если вы используете этот метод: return View("Index", viewModel)
@mkozicki, с удаленной проверкой не работает. Пожалуйста, помогите справиться с несколькими кнопками с удаленной проверкой.
@KomalJariwala Ответы на ваш вопрос здесь может вам в этом помочь.
Я вижу загрузку специального / дополнительного кода по этому вопросу, но стандарты w3.org html уже охватили этот бит, см. Мой ответ полностью. Минимальный код, максимальный результат, мой любимый вид.
У меня не работает. Потратил много времени, играя с этим. Возвращается ни с чем, но вызывает getvalue.
Самая большая проблема с несколькими кнопками отправки - первая отправка всегда запускается при возврате каретки. Это требует, чтобы javascript обнаруживал нажатия кнопок, и оттуда все становится беспорядочно.
просто информация, нам нужно добавить system.Reflection для MethodInfo
Почему controllerContext.Controller.ControllerContext.RouteData? Разве это не то же самое, что просто controllerContext.RouteData?
Не могу заставить это работать. controllerContext.Controller.ValueProvider.GetValue (keyValue) всегда имеет значение NULL. Кнопка - <button id = "buttonNotesSave" type = "submit" value = "NotesSave" name = "action: CustomerNotes"> - Использование контроллера - [MultipleButton (Name = "action", Argument = "CustomerNotes" )] - Кто-нибудь может помочь?
Работает чертовски хорошо в MVC 5.2.3 Cheers.
@mkozicki, я пробовал в IE, не сработало. У меня ошибка 404, но в хроме она работает. Есть предположения?
@Yass Не уверен, почему это не работает в IE, но проверьте, что IsValidName попадает, и какие значения для Name и Argument. Возможно, IE не включает значение отправки в запрос.
Очень хорошо работает как в IE, так и в Chrome
Это все еще действительно в ASP.net 5 MVC 6? Я получаю сообщение об ошибке ActionNameSelectorAttribute not found при использовании в ASP.net 5.
Я использую MVC 5.2.3, он работает в IE11, но в Chrome кнопки не появляются в FormValueProvider. :(
@ Санджу. Убедитесь, что у вас есть следующие операторы using using System; using System.Reflection; using System.Web.Mvc;
@Kaan, мне не удалось воспроизвести вашу проблему в новом проекте.
@mkozicki, вообще-то я нашел проблему. Причина, по которой он не работает, заключается в методах submitHandler jquery.validation. Если вы им не пользуетесь - отлично.
Он работает до тех пор, пока я не вызову перенаправление из действия ... Я получил ошибку «Дочерним действиям не разрешено выполнять действия перенаправления»
@Anton Это может помочь: stackoverflow.com/questions/25015833/…
при наследовании ActionNameSelectorAttribute для MultipleSubmitButtonAttribute не удалось найти определение. пожалуйста, может ли кто-нибудь сказать ему, как разрешить красную волнистую линию и какие операторы использования я должен использовать.
У меня отлично работает при работе с несколькими кнопками. У меня только одна проблема: допустим, я также хочу вызвать действие вручную с помощью $.post(path/to/controller/test). Это вызовет ошибку: на контроллере не найдено подходящего действия ... Мне нужно добавить действие: проверить вручную, чтобы заставить его работать. Что-то вроде $.post(path/to/controller/test, [{ name: 'action:test', value: '' }]), чтобы заставить его работать. Есть ли способ сделать звонок вручную?
@Tom У вас должна быть возможность напрямую сопоставить маршрут с действием, которое вы хотите вызвать. В противном случае реализация зависит от установленного атрибута name='action:test'.
@mkozicki Большое спасибо, все работает отлично, мне очень помогло.
@ boilers222 Привет, у меня сейчас та же проблема, но она работала 111 дней назад, когда я ее реализовал. Удалось ли вам решить нулевую проблему, и если да, то каково было решение (если вы помните). Спасибо!
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue) всегда возвращает null.
привет @mkozicki .. не могли бы вы предоставить мне демонстрационную ссылку для этого
не работает для меня, не знаю, почему он всегда отправляет меня в контроллер индекса
Я думаю, что добавить параметр к действию публикации под названием «submit» проще, чем это. Отметьте это binaryintellect.net/articles/…
Моя единственная проблема - это URL-адрес, который остается прежним. ex http://localhost:66666/MaterialRequisition/Step1 для этапа 2 и этапа 3; тьфу у меня 3 кнопки ПредыдущийСледующийОтмена
Это еще один полезный ссылка на сайт
Мой подход 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')" >
Если у вас нет ограничений на использование HTML 5, вы можете использовать тег <button> с атрибутом formaction:
<form action = "demo_form.asp" method = "get">
First name: <input type = "text" name = "fname" /><br />
Last name: <input type = "text" name = "lname" /><br />
<button type = "submit">Submit</button><br />
<button type = "submit" formaction = "demo_admin.asp">Submit as admin</button>
</form>
Ссылка: http://www.w3schools.com/html5/att_button_formaction.asp
это лучший способ, который я нашел:
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);
}
}
}
Наслаждайтесь будущим с несколькими кнопками отправки без запаха кода.
Спасибо
Ссылка в настоящее время не работает, это ближайшая архивная версия, которую я смог найти: web.archive.org/web/20110706230408/http://blogs.sonatribe.co м /…
Привет, Ян - спасибо, что раскопал - я разместил его здесь: iwayneo.blogspot.co.uk/2013/10/…
Вот что мне лучше всего подходит:
<input type = "submit" value = "Delete" name = "onDelete" />
<input type = "submit" value = "Save" name = "onSave" />
public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
if (onDelete != null)
{
// Delete the object
...
return EmptyResult();
}
// Save the object
...
return EmptyResult();
}
Я получаю нулевое значение для onDelete и onSave в методе контроллера. Ты знаешь почему?
Любой из них не будет нулевым, если вы нажмете соответствующую кнопку. Какую кнопку вы нажимаете, чтобы получить нуль?
Мое решение заключалось в использовании 2 панелей asp:
<asp:Panel ID=”..” DefaultButton=”ID_OF_SHIPPING_SUBMIT_BUTTON”….></asp:Panel>
Этот скрипт позволяет указать атрибут data-form-action, который будет работать как атрибут HTML5 formaction во всех браузерах (ненавязчиво):
$(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);
});
Форма, содержащая кнопку, будет отправлена по URL-адресу, указанному в атрибуте data-form-action:
<button type = "submit" data-form-action = "different/url">Submit</button>
Для этого требуется jQuery 1.7. Для предыдущих версий вы должны использовать live() вместо on().
Для каждой кнопки отправки просто добавьте:
$('#btnSelector').click(function () {
$('form').attr('action', "/Your/Action/);
$('form').submit();
});
Я попытался синтезировать все решения и создал атрибут [ButtenHandler], который упрощает работу с несколькими кнопками в форме.
Я описал это на CodeProject Множественные параметризованные (локализуемые) кнопки формы в ASP.NET MVC.
Чтобы справиться с простым случаем этой кнопки:
<button type = "submit" name = "AddDepartment">Add Department</button>
У вас будет что-то вроде следующего метода действий:
[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
model.Departments.Add(new Department());
return View(model);
}
Обратите внимание, как имя кнопки совпадает с именем метода действия. В статье также описывается, как иметь кнопки со значениями и кнопки с индексами.
У меня недостаточно репутации, чтобы оставлять комментарии в нужном месте, но я потратил на это весь день, поэтому хочу поделиться.
При попытке реализовать решение "MultipleButtonAttribute" ValueProvider.GetValue(keyValue) некорректно возвращал null.
Оказалось, что я ссылался на System.Web.MVC версии 3.0, тогда как она должна была быть 4.0 (другие сборки - 4.0). Я не знаю, почему мой проект не обновился правильно, и у меня не было других очевидных проблем.
Так что, если ваш ActionNameSelectorAttribute не работает ... проверьте это.
//model
public class input_element
{
public string Btn { get; set; }
}
//views--submit btn can be input type also...
@using (Html.BeginForm())
{
<button type = "submit" name = "btn" value = "verify">
Verify data</button>
<button type = "submit" name = "btn" value = "save">
Save data</button>
<button type = "submit" name = "btn" value = "redirect">
Redirect</button>
}
//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();
}
Возможно, вы этого не осознавали, но этот же ответ на этот вопрос уже публиковался несколько раз.
Кроме того, вы, кажется, публикуете ответы, которые содержат только код без объяснения причин. Не могли бы вы добавить немного повествования, чтобы объяснить, почему код работает и что делает его ответом на вопрос? Это будет очень полезно для человека, задающего вопрос, и для всех, кто придет к вам на помощь.
Конечно, работает нормально. Но этот ответ был уже было дано другими давным-давно. И они включили пояснения по поводу Зачем, он тоже работает.
Основываясь на ответе 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;
}
}
Посмотреть
<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.
Модифицированная версия метода HttpParamActionAttribute, но с исправлением ошибки, не вызывающей ошибки при просроченных / недействительных обратных передачах сеанса. Чтобы узнать, не проблема ли это с вашим текущим сайтом, откройте форму в окне и перед тем, как перейти, щелкните Save или Publish, откройте дублирующееся окно и выйдите из системы. Теперь вернитесь в свое первое окно и попробуйте отправить форму, используя любую кнопку. У меня возникла ошибка, поэтому это изменение решает эту проблему для меня. Я опускаю кучу вещей для краткости, но вы должны уловить идею. Ключевыми частями являются включение ActionName в атрибут и обеспечение того, чтобы переданное имя было именем представления, которое показывает форму.
Атрибут Класс
[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");
}
Вид
@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" />
}
Что мне не нравится в 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" />
Если ваш браузер поддерживает атрибут formaction для кнопок ввода (IE 10+, не уверен в других браузерах), то должно работать следующее:
@using (Html.BeginForm()){
//put form inputs here
<input id = "sendBtn" value = "Send" type = "submit" formaction = "@Url.Action("Name Of Send Action")" />
<input id = "cancelBtn" value = "Cancel" type = "submit" formaction = "@Url.Action("Name of Cancel Action") />
}
Взгляните на мой ответ ниже, он не зависит от черновых спецификаций. Ваш ответ допускает возможность иметь разные URL-адреса действий, а у меня нет.
Я тоже столкнулся с этой «проблемой», но нашел довольно логичное решение, добавив атрибут name. Я не мог вспомнить, чтобы у меня была эта проблема на других языках.
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
Это означает, что следующие атрибуты кода value могут быть изменены, локализованы, интернационализированы без нужно для дополнительной проверки кода строго типизированных файлов ресурсов или констант.
<% 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(); %>`
На принимающей стороне вам нужно будет только проверить, не является ли какой-либо из ваших известных типов отправки 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
}
}
Это решение, которое мы решили использовать для простого веб-приложения, в котором нам нужна была функциональность ASP.NET WebForms, но в рамках MVC.
Index.cshtml
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "submitForm" }))
{
button type = "submit" id = "btnApprove" name = "Command" value = "Approve"> Approve
button type = "submit" id = "btnReject" name = "Command" value = "Reject"> Reject
}
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(FormCollection frm, string Command)
{
if (Command == "Approve")
{
}
else if (Command == "Reject")
{
}
return View();
}
}
При использовании форм ajax мы можем использовать ActionLinks с POST HttpMethod и сериализуйте форму в событии AjaxOptions.OnBegin.
Допустим, у вас есть два действия, InsertAction и UpdateAction:
<form>
@Html.Hidden("SomeField", "SomeValue")
@Ajax.ActionLink(
"Insert",
"InsertAction",
null,
new AjaxOptions {
OnBegin = "OnBegin",
UpdateTargetId = "yourDiv",
HttpMethod = "POST" })
@Ajax.ActionLink(
"Update",
"UpdateAction",
null,
new AjaxOptions {
OnBegin = "OnBegin",
UpdateTargetId = "yourDiv",
HttpMethod = "POST" })
</form>
Javascript
function OnBegin(xhr, settings) {
settings.data = $("form").serialize();
}
Есть три способа решить указанную выше проблему.
Ниже приведено видео, в котором наглядно представлены все три подхода.
https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940
HTML способ: -
В формате HTML нам нужно создать две формы и поместить кнопку «Отправить» внутри каждой из форм. И действие каждой формы будет указывать на разные / соответствующие действия. Вы можете увидеть приведенный ниже код: первая форма отправляет сообщение в «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», см. Код ниже. Эти функции будут выполнять вызовы Ajax с помощью JQUERY или любой другой инфраструктуры. Каждая из этих функций связана с событиями 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 нам нужно присвоить кнопкам отправки собственные имена, чтобы их можно было идентифицировать на сервере.
Вы можете видеть, что мы добавили «Сохранить» и «Удалить» к названиям кнопок. Также вы можете заметить, что в действии мы просто указали имя контроллера «Клиент», а не конкретное имя действия. Мы ожидаем, что название действия будет определяться «ActionNameSelectorAttribute».
<form action=”Customer” method=post>
<input type=submit value = "Save" name = "Save" /> <br />
<input type=submit value = "Delete" name = "Delete"/>
</form>
Поэтому, когда нажимается кнопка отправки, она сначала попадает в атрибут «ActionNameSelector», а затем, в зависимости от того, какая отправка запущена, вызывает соответствующее действие.

Итак, первым шагом является создание класса, который наследуется от класса «ActionNameSelectorAttribute». В этом классе мы создали простое свойство «Имя».
Нам также необходимо переопределить функцию «IsValidName», которая возвращает true или flase. В этой функции мы пишем логику, нужно ли выполнять действие или нет. Итак, если эта функция возвращает истину, действие выполняется, иначе - нет.
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");
}
}
Я создал метод ActionButton для HtmlHelper. Он сгенерирует обычную кнопку ввода с битом javascript в Событие OnClick, которая отправит форму указанному контроллеру / действию.
Вы так используете помощника
@Html.ActionButton("MyControllerName", "MyActionName", "button text")
это сгенерирует следующий HTML
<input type = "button" value = "button text" onclick = "this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();">
Вот код метода расширения:
VB.Net
<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));
}
Эти методы имеют различные параметры, но для простоты использования вы можете создать некоторую перегрузку, которая принимает только нужные вам параметры.
Я довольно поздно на вечеринку, но вот ... Моя реализация заимствована из @mkozicki, но требует меньше жестко запрограммированных строк, чтобы ошибиться. Требуется Framework 4.5+. По сути, имя метода контроллера должно быть ключом к маршрутизации.
Разметка. Название кнопки должно быть связано с "action:[controllerMethodName]".
(обратите внимание на использование C# 6 Имя API, предоставляющего зависящую от типа ссылку на имя метода контроллера, который вы хотите вызвать.
<form>
... form fields ....
<button name = "action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type = "submit" formmethod = "post">Fund Death Star</button>
<button name = "action:@nameof(MyApp.Controllers.MyController.HireBoba)" type = "submit" formmethod = "post">Hire Boba Fett</button>
</form>
Контроллер:
namespace MyApp.Controllers
{
class MyController
{
[SubmitActionToThisMethod]
public async Task<ActionResult> FundDeathStar(ImperialModel model)
{
await TrainStormTroopers();
return View();
}
[SubmitActionToThisMethod]
public async Task<ActionResult> 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;
}
}
Хотя это хороший подход, вы не сможете использовать встроенный связыватель модели mvc, потому что он использует атрибут «name» кнопки.
Цель этого решения - обойти пост-маршрутизацию MVC. Опишите улучшение.
Используйте настраиваемый помощник (создайте файл Helpers.cshtml внутри папки App_Code в корне вашего проекта) с javascript, чтобы переписать (при событии onclick) атрибут action формы на то, что вы хотите, а затем отправить Это.
Помощник может быть таким:
@helper SubmitButton(string text, string controller,string action)
{
var uh = new System.Web.Mvc.UrlHelper(Context.Request.RequestContext);
string url = @uh.Action(action, controller, null);
<input type=button onclick = "(
function(e)
{
$(e).parent().attr('action', '@url'); //rewrite action url
//create a submit button to be clicked and removed, so that onsubmit is triggered
var form = document.getElementById($(e).parent().attr('id'));
var button = form.ownerDocument.createElement('input');
button.style.display = 'none';
button.type = 'submit';
form.appendChild(button).click();
form.removeChild(button);
}
)(this)" value = "@text"/>
}
А затем используйте его как:
@Helpers.SubmitButton("Text for 1st button","ControllerForButton1","ActionForButton1")
@Helpers.SubmitButton("Text for 2nd button","ControllerForButton2","ActionForButton2")
...
Внутри вашей формы.
это коротко и люкс:
It was answered by Jeroen Dop
<input type = "submit" name = "submitbutton1" value = "submit1" />
<input type = "submit" name = "submitbutton2" value = "submit2" />
и сделайте это в коде за
if ( Request.Form["submitbutton1"] != null)
{
// Code for function 1
}
else if (Request.Form["submitButton2"] != null )
{
// code for function 2
}
Удачи.
Потрясающие. именно то, что я делал в веб-формах. Ура приятель
Намного проще, чем верхний ответ! Спасибо!
[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
{
var button = nameValueResend ?? nameValueSubmit;
if (button == "Resend")
{
}
else
{
}
}
Razor file Content:
@using (Html.BeginForm()
{
<div class = "page registration-result-page">
<div class = "page-title">
<h1> Confirm Mobile Number</h1>
</div>
<div class = "result">
@Html.EditorFor(model => model.VefificationCode)
@Html.LabelFor(model => model.VefificationCode, new { })
@Html.ValidationMessageFor(model => model.VefificationCode)
</div>
<div class = "buttons">
<button type = "submit" class = "btn" name = "nameValueResend" value = "Resend">
Resend
</button>
<button type = "submit" class = "btn" name = "nameValueSubmit" value = "Verify">
Submit
</button>
</div>
</div>
}
Это еще один полезный ссылка на сайт, объясняющий различные способы создания сообщений.
Стоит упомянуть начиная с ASP.NET Core есть гораздо более простые решения, чем перечисленные здесь.