Как вы обрабатываете несколько кнопок отправки в ASP.NET MVC Framework?

Есть ли простой способ обрабатывать несколько кнопок отправки из одной формы? Например:

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

Есть идеи, как это сделать в бета-версии ASP.NET Framework? Во всех примерах, которые я искал в Google, есть отдельные кнопки.

Стоит упомянуть начиная с ASP.NET Core есть гораздо более простые решения, чем перечисленные здесь.

Steven Jeuris 16.02.2017 03:37

Этот учебник может помочь: Отправка формы в различные методы действий в ASP.NET MVC

Hooman Bahreini 10.09.2019 05:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
748
2
451 143
35
Перейти к ответу Данный вопрос помечен как решенный

Ответы 35

Вы должны иметь возможность давать кнопкам имена и значения; затем сопоставьте это имя как аргумент действия. В качестве альтернативы используйте 2 отдельные ссылки действия или 2 формы.

Безусловно, самое чистое и простое решение, которое я когда-либо видел.

Jason Evans 10.02.2015 14:11

Вы могли написать:

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

А затем на странице проверьте, есть ли имя == «Отправить» или имя == «Отменить» ...

Хотя это работает, но я считаю неправильной практикой иметь два элемента с одинаковыми именами.

Péter 05.07.2013 15:25

Это не обязательно неправильно. Это зависит от того, как вы используете входы. У вас может быть несколько элементов с одинаковым именем и ожидание получения нескольких данных (так работают радиокнопки и флажки). Но да, если вы используете этот метод, это потому, что вы делаете это «неправильно» ... Вот почему я поставил «Вы могли бы», но не «Вы должны»: P

Ironicnet 30.08.2013 22:29

Вы можете проверить имя в действии, как уже упоминалось, но вы можете подумать, хороший ли это дизайн. Хорошая идея - учитывать ответственность за действие и не связывать этот дизайн слишком сильно с такими аспектами пользовательского интерфейса, как названия кнопок. Поэтому рассмотрите возможность использования 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") %>

Это нормально, если вам не нужны одни и те же данные формы для каждой кнопки отправки. Если вам нужны все данные в единой форме, то вам подойдет Дилан Битти. Есть ли более элегантный способ сделать это?

zidane 28.09.2009 13:30

Насчет визуального представления, как в этом случае кнопка «Отправить» рядом с кнопкой «Отменить»?

Kris-I 09.03.2011 07:49

Дилан: Что ж, для кнопки отмены вам вообще не нужно отправлять данные, и связывать контроллер с элементами пользовательского интерфейса - плохая практика. Однако, если вы можете создать более или менее общую «команду», я думаю, что это нормально, но я бы не привязывал ее к «submitButton», поскольку это имя элемента пользовательского интерфейса.

Trevor de Koekkoek 16.03.2011 18:08

@Kris: вы можете размещать свои кнопки с помощью CSS, и они по-прежнему могут находиться в двух разных разделах формы.

Trevor de Koekkoek 16.03.2011 18:10

Я думаю, здесь следует упомянуть, что если класс контроллера называется MyController, второй параметр должен читать не MyController, а просто My, поскольку предполагается, что часть имени контролер.

Niklas 01.11.2011 19:17

шутки в сторону? это не пахнет никому, кроме меня ?!

user156888 24.11.2011 15:48

Я не могу понять, почему это было выбрано как правильный ответ. HTML5 поддерживает formaction для отправки формы по разным URL-адресам, поэтому я подозреваю, что это не такая уж плохая идея ...

JotaBe 16.05.2013 16:21

По сути, это ответ на актуальный вопрос. И всего этого можно добиться, просто используя значения маршрута. Пока он не публикует никаких фактических данных. Так что я собираюсь проголосовать за это.

Worthy7 02.08.2016 09:25

Дайте вашим кнопкам отправки имя, а затем проверьте отправленное значение в методе вашего контроллера:

<% 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/… - спасибо

paulwhit 17.03.2009 05:44

жаль, что вы зависите от текста, отображаемого на кнопке, это довольно сложно с многоязычным пользовательским интерфейсом

Omu 22.04.2010 15:52

Ому - см. Последнее изменение, в котором объясняется (вкратце!), Как сделать то же самое с локализованными ресурсами строк / сообщений.

Dylan Beattie 22.04.2010 16:36

Переключатель / регистр работает только с константами, поэтому в локализованной версии нельзя использовать переключатель / регистр. Вам нужно переключиться на if else или другой метод отправки.

mlibby 01.11.2010 23:58

Взгляните на решение от Izmoto с использованием атрибута MultiButton, оно кажется очень хорошим.

Simon Keep 02.11.2010 18:31

@mcl - ты абсолютно прав. Код был отредактирован для использования if / else вместо switch () для локализованной версии. Спасибо.

Dylan Beattie 03.11.2010 14:38

А как насчет проверки формы? Некоторые кнопки могут не требовать полной проверки формы.

Eduardo 17.06.2011 19:08

@DylanBeattie, что, если представление состоит из частичных представлений, и вы хотите проверить представление? Означает, что каждая кнопка отправки будет соответствовать другому представлению, и связанное действие должно сначала подтвердить представление. Главное действие проверит все частичные представления перед продолжением.

bjan 29.02.2012 16:06

@DylanBeattie: Что, если я хочу передать модель в качестве параметра моему методу действия? Могу ли я получить название кнопки в этом случае?

Biki 29.05.2012 09:17

@Biki - да, просто привяжите значение кнопки в качестве параметра вашей модели. В нескольких местах я разделил конкретную модель на явные ViewModel и PostModel - затем вы вызываете кнопку отправки примерно так: <input type = "submit" name = "model.SubmitButton" value = "Yada" />, а затем передать (модель PostModel) в метод вашего контроллера, и вы должны обнаружить, что значение кнопки доступно в model.SubmitButton.

Dylan Beattie 29.05.2012 13:42

вам следует использовать <button type = "submit" вместо <input type, потому что значение типа кнопки <не является текстом;). Тогда у вас может получиться что-то вроде этого: <button name = "mySubmitButton" type = "submit" value = "keyValue"> YourButtonText </button>

J4N 29.05.2012 16:32

@iwayneo, интересное решение. Когда я зашел туда, сайт не работал, но на обратном пути он был: web.archive.org/web/20110312212221/http://blogs.sonatribe.co‌ м /…

Darren Griffith 01.03.2013 04:22

А как насчет захвата всей модели в контроллере в дополнение к кнопке отправки (строка submitButton)?

crichavin 20.03.2013 06:05

Как это будет работать с передачей модели в действие, а не просто значение отправки?

bizzehdee 07.08.2013 11:56

см. также stackoverflow.com/questions/4171664/…, чтобы узнать, как создать кнопку, текст которой может отличаться от представленного значения

Simon_Weaver 09.12.2013 06:21

Будьте осторожны и не называйте кнопки «действием», если вы используете jQuery. Это вызывает конфликт в библиотеке, который нарушает URL-адрес действия.

HotN 15.10.2014 01:20

Чтобы ответить от @bizzehdee, просто передайте модель в качестве первого параметра и имя кнопки отправки в качестве второго параметра.

KingOfHypocrites 18.11.2014 23:56

Этот подход намного проще, чем безумные штучки с настраиваемыми атрибутами. Принцип KISS для победы.

Graham 23.01.2015 19:46

-1, на практике я вижу, что такой подход приводит к ужасному коду. Во-первых, вам становится трудно следовать логике, а во-вторых, вам приходится принимать все параметры, необходимые для каждого конкретного метода, что приводит к массовому объявлению метода. Подход с настраиваемыми атрибутами - это подход KISS! Если вам не нравятся настраиваемые атрибуты, ASP.NET не для вас ...

Ian Newson 31.03.2015 18:51

@DylanBeattie Есть ли хороший способ передать идентификатор (кнопка удаления с идентификатором)?

patrick 29.02.2016 17:51

Эйлон предлагает сделать это так:

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.

Kugel 12.06.2013 05:28

Как бы вы это сделали, если бы создавали в этой форме вызов ajax. Кажется, что form.serialize () не подбирает имя кнопки отправки ..

mko 15.09.2014 18:15

@Kugel прав, это все еще самый чистый ответ. Спасибо

Arif YILMAZ 31.10.2016 15:42

Дэвид Финдли в своем блоге 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 транслируется непосредственно в дискретный метод действия на вашем контроллере.

Kirk Woll 26.10.2011 08:29

+1 Для меня это однозначно лучшее решение этой проблемы. Поскольку я реализовал это, я заметил, что через HttpParamActionAttribut проходит много трафика, но по сравнению со всеми другими вещами, которые Asp.Net MVC должен делать при обработке запроса, это вполне приемлемо. Чтобы взломать только то, что мне нужно сделать, это поместить пустое «Действие» с именем в моем контроллере, чтобы Resharper не предупреждал меня о том, что действие «Действие» не существует. Большое спасибо!

Samuel 18.01.2013 22:39

Я просмотрел все решения и согласен, что это красивое, элегантное и простое решение. Отлично, что нет условных операторов и надежных, где вы можете определить новое действие контроллера, когда у вас есть новая кнопка. Называется мой класс MultiButtonActionHandler FYI ;-)

ejhost 21.04.2015 22:30

Предлагаю заинтересованным сторонам взгляните на решение Maarten Balliauw. Я считаю, что это очень элегантно.

В случае, если ссылка пропадает, он использует атрибут MultiButton, примененный к действию контроллера, чтобы указать, к какому нажатию кнопки должно относиться это действие.

Это решение, которое мы используем сейчас, и оно очень удобное. Это только MVC 2?

Simon Keep 02.11.2010 18:30

Это прекрасно! Я такого раньше не видел! Хотя я согласен с тем, что вы можете захотеть переделать любое решение, использующее несколько отправок, чтобы использовать только одну кнопку, я нахожусь в затруднительном положении и должен это сделать. Этот ответ должен был победить!

Rikon 30.09.2011 18:19

Это отличное решение. Очень чистый

Omnia9 24.10.2011 17:42

Пробовал этот подход и не смог заставить его работать в MVC3. У меня сработал вариант получателя голосов №1.

Scott Lawrence 03.10.2012 23:36

Коротко и мило .. но не для mvc 3+

Piotr Kula 19.07.2013 00:23

Это еще один полезный ссылка на сайт, объясняющий различные способы создания сообщений.

Himalaya Garg 21.10.2019 10:38

Я бы использовал эту технику, но я ее здесь пока не вижу. Ссылка (опубликована Сааджидом Исмаилом ), который вдохновляет на это решение, является 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;
         }
    }
}

Похоже, решение Ироникнет предоставил.

Kris van der Mast 02.11.2010 18:02

Конечно, похоже, но здесь показаны как локализация, так и код контроллера, чего я не видел в этом потоке. Я нашел эту ветку, когда искал, как это сделать, и хотел задокументировать то, что я придумал, для всех, кто может оказаться в той же лодке.

mlibby 03.11.2010 14:56

На самом деле, это не то же самое, что и Ironicnet, кроме этого. Он использует элементы <input>. Я использую <button>, который требуется для локализации без атрибутов значений переменных.

mlibby 03.11.2010 14:59

Вот метод расширения, который я написал для обработки нескольких кнопок с изображениями и / или текстом.

Вот 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".

Мне нравится проверять имя в качестве альтернативы, потому что вы не всегда можете проверить значение, например. у вас есть список элементов, и у каждого есть кнопка «Удалить».

Max 26.08.2011 15:09

В представлении код:

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

В будущем вам будет полезно объяснять свой код. Спасибо!

user1131435 16.03.2014 11:12
Ответ принят как подходящий

Вот в основном чистое решение проблемы с несколькими кнопками отправки на основе атрибутов, в значительной степени основанное на публикации и комментариях от 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, похоже, обеспечивает ту же функциональность из коробки. Для новых разработок это может быть предпочтительнее.

Я нашел это решение счастливым браком с другими используемыми техниками. Отлично работает и не влияет на локализацию.

trevorc 30.11.2011 02:33

Отличное решение !! Гораздо полезнее, чем эти самые популярные ответы

Sasha 16.02.2012 21:23

что такое строка 'value = new ValueProviderResult (Argument, Argument, null);' используется для? Это кажется лишним.

Rebecca 09.01.2013 17:48

Я пытаюсь реализовать это, но это не работает. Похоже, что атрибут никогда не попадает. Он идет прямо в мой контроллер индекса. Есть идеи, почему?

Adelia Benalius 25.02.2013 14:00

@AdeLia У меня не было проблем с просто декорированием методов атрибутом MultipleSubmit. Я рад помочь, но для этого мне нужна дополнительная информация (код, разметка и т. д.).

mkozicki 05.03.2013 21:08

@mkozicki Похоже, это произошло потому, что у меня был класс MultipleButtonAttribute в другом проекте. Как только я помещаю его в тот же проект, он работает. Странно, я бы не подумал, что это будет проблемой, если ссылка верна.

Adelia Benalius 12.03.2013 16:37

Мне нравится, мило и чисто, мне придется добавить это в свой набор инструментов

Chris McGrath 19.04.2013 09:14

Дааааааааа. Работает на MVC 4.5. Другой, похоже, не работает. отлично +1

Piotr Kula 19.07.2013 00:35

Проблема с этим подходом заключается в том, что если вы попытаетесь выполнить return View(viewmodel) в случае, когда ваша модель имеет ошибки, она попытается вернуть представление с именем Send или в зависимости от имени вашего аргумента.

James Sampica 17.10.2013 20:03

@Shoe - только что нашел похожую вещь. Убедитесь, что вы явно указали имя представления, которое нужно вернуть, если вы используете этот метод: return View("Index", viewModel)

ajbeaven 28.11.2013 01:08

@mkozicki, с удаленной проверкой не работает. Пожалуйста, помогите справиться с несколькими кнопками с удаленной проверкой.

KomalJariwala 25.01.2014 16:56

@KomalJariwala Ответы на ваш вопрос здесь может вам в этом помочь.

mkozicki 27.01.2014 18:57

Я вижу загрузку специального / дополнительного кода по этому вопросу, но стандарты w3.org html уже охватили этот бит, см. Мой ответ полностью. Минимальный код, максимальный результат, мой любимый вид.

Tom Hofman 30.04.2014 16:05

У меня не работает. Потратил много времени, играя с этим. Возвращается ни с чем, но вызывает getvalue.

KingOfHypocrites 18.11.2014 23:27

Самая большая проблема с несколькими кнопками отправки - первая отправка всегда запускается при возврате каретки. Это требует, чтобы javascript обнаруживал нажатия кнопок, и оттуда все становится беспорядочно.

Chris Hawkes 29.01.2015 22:41

просто информация, нам нужно добавить system.Reflection для MethodInfo

Vignesh Subramanian 01.04.2015 14:06

Почему controllerContext.Controller.ControllerContext.RouteData? Разве это не то же самое, что просто controllerContext.RouteData?

Tobias J 15.05.2015 20:28

Не могу заставить это работать. controllerContext.Controller.ValueProvider.GetValue (keyValue‌) всегда имеет значение NULL. Кнопка - <button id = "buttonNotesSave" type = "submit" value = "NotesSave" name = "action: CustomerNotes"> - Использование контроллера - [MultipleButton (Name = "action", Argument = "CustomerNotes" )] - Кто-нибудь может помочь?

boilers222 08.07.2015 18:16

Работает чертовски хорошо в MVC 5.2.3 Cheers.

Aaron Hudon 07.11.2015 07:28

@mkozicki, я пробовал в IE, не сработало. У меня ошибка 404, но в хроме она работает. Есть предположения?

Yass 19.01.2016 05:50

@Yass Не уверен, почему это не работает в IE, но проверьте, что IsValidName попадает, и какие значения для Name и Argument. Возможно, IE не включает значение отправки в запрос.

mkozicki 20.01.2016 19:56

Очень хорошо работает как в IE, так и в Chrome

Nirman 25.01.2016 12:08

Это все еще действительно в ASP.net 5 MVC 6? Я получаю сообщение об ошибке ActionNameSelectorAttribute not found при использовании в ASP.net 5.

skjoshi 14.02.2016 18:55

Я использую MVC 5.2.3, он работает в IE11, но в Chrome кнопки не появляются в FormValueProvider. :(

Kaan 15.02.2016 18:29

@ Санджу. Убедитесь, что у вас есть следующие операторы using using System; using System.Reflection; using System.Web.Mvc;

mkozicki 16.02.2016 00:17

@Kaan, мне не удалось воспроизвести вашу проблему в новом проекте.

mkozicki 16.02.2016 00:18

@mkozicki, вообще-то я нашел проблему. Причина, по которой он не работает, заключается в методах submitHandler jquery.validation. Если вы им не пользуетесь - отлично.

Kaan 16.02.2016 14:55

Он работает до тех пор, пока я не вызову перенаправление из действия ... Я получил ошибку «Дочерним действиям не разрешено выполнять действия перенаправления»

Anton 21.05.2016 23:59

@Anton Это может помочь: stackoverflow.com/questions/25015833/…

mkozicki 25.05.2016 17:52

при наследовании ActionNameSelectorAttribute для MultipleSubmitButtonAttribute не удалось найти определение. пожалуйста, может ли кто-нибудь сказать ему, как разрешить красную волнистую линию и какие операторы использования я должен использовать.

alamin 27.05.2016 07:42

У меня отлично работает при работе с несколькими кнопками. У меня только одна проблема: допустим, я также хочу вызвать действие вручную с помощью $.post(path/to/controller/test). Это вызовет ошибку: на контроллере не найдено подходящего действия ... Мне нужно добавить действие: проверить вручную, чтобы заставить его работать. Что-то вроде $.post(path/to/controller/test, [{ name: 'action:test', value: '' }]), чтобы заставить его работать. Есть ли способ сделать звонок вручную?

Tom 28.07.2016 11:34

@Tom У вас должна быть возможность напрямую сопоставить маршрут с действием, которое вы хотите вызвать. В противном случае реализация зависит от установленного атрибута name='action:test'.

mkozicki 01.08.2016 17:44

@mkozicki Большое спасибо, все работает отлично, мне очень помогло.

gdmanandamohon 09.09.2016 07:14

@ boilers222 Привет, у меня сейчас та же проблема, но она работала 111 дней назад, когда я ее реализовал. Удалось ли вам решить нулевую проблему, и если да, то каково было решение (если вы помните). Спасибо!

ᴍᴀᴛᴛ ʙᴀᴋᴇʀ 07.11.2016 13:06
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue‌​) всегда возвращает null.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ 07.11.2016 15:48

привет @mkozicki .. не могли бы вы предоставить мне демонстрационную ссылку для этого

Mohd Aman 12.01.2017 09:05

не работает для меня, не знаю, почему он всегда отправляет меня в контроллер индекса

Gusti Arya 25.04.2017 10:28

Я думаю, что добавить параметр к действию публикации под названием «submit» проще, чем это. Отметьте это binaryintellect.net/articles/…

Damitha 30.06.2017 18:29

Моя единственная проблема - это URL-адрес, который остается прежним. ex http://localhost:66666/MaterialRequisition/Step1 для этапа 2 и этапа 3; тьфу у меня 3 кнопки ПредыдущийСледующийОтмена

j1rjacob 01.02.2019 23:03

Это еще один полезный ссылка на сайт

Himalaya Garg 21.10.2019 10:37

Мой подход 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‌ м /…

Ian Kemp 25.10.2013 19:09

Привет, Ян - спасибо, что раскопал - я разместил его здесь: iwayneo.blogspot.co.uk/2013/10/…

user156888 28.10.2013 14:57

Вот что мне лучше всего подходит:

<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 в методе контроллера. Ты знаешь почему?

Diganta Kumar 24.01.2013 06:30

Любой из них не будет нулевым, если вы нажмете соответствующую кнопку. Какую кнопку вы нажимаете, чтобы получить нуль?

Sergey 08.07.2013 21:50

Мое решение заключалось в использовании 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();
        }

Возможно, вы этого не осознавали, но этот же ответ на этот вопрос уже публиковался несколько раз.

Andrew Barber 26.02.2013 09:39

Кроме того, вы, кажется, публикуете ответы, которые содержат только код без объяснения причин. Не могли бы вы добавить немного повествования, чтобы объяснить, почему код работает и что делает его ответом на вопрос? Это будет очень полезно для человека, задающего вопрос, и для всех, кто придет к вам на помощь.

Andrew Barber 26.02.2013 09:41

Конечно, работает нормально. Но этот ответ был уже было дано другими давным-давно. И они включили пояснения по поводу Зачем, он тоже работает.

Andrew Barber 26.02.2013 09:49

Основываясь на ответе 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-адреса действий, а у меня нет.

Tom Hofman 30.04.2014 16:10

Я тоже столкнулся с этой «проблемой», но нашел довольно логичное решение, добавив атрибут 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.

BrandonG 14.09.2016 23:17

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

Есть три способа решить указанную выше проблему.

  1. HTML способ
  2. JQuery способ
  3. Способ «ActionNameSelectorAttribute»

Ниже приведено видео, в котором наглядно представлены все три подхода.

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» кнопки.

ooXei1sh 18.06.2016 00:15

Цель этого решения - обойти пост-маршрутизацию MVC. Опишите улучшение.

Aaron Hudon 18.06.2016 07:03

Используйте настраиваемый помощник (создайте файл 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
}

Удачи.

Потрясающие. именно то, что я делал в веб-формах. Ура приятель

djack109 10.07.2017 09:50

Намного проще, чем верхний ответ! Спасибо!

pabben 15.10.2018 21:53
[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>

    }

Это еще один полезный ссылка на сайт, объясняющий различные способы создания сообщений.

Himalaya Garg 21.10.2019 10:38

Другие вопросы по теме