Как вы обрабатываете несколько кнопок отправки в 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 Beta? Все примеры, на которые я гуглил, содержат отдельные кнопки.

14.01.2009 11:58:36
Стоит отметить, что начиная с ASP.NET Core, есть гораздо более простые решения, чем перечисленные здесь.
Steven Jeuris 16.02.2017 00:37:35
Hooman Bahreini 10.09.2019 02:01:45
30 ОТВЕТОВ
РЕШЕНИЕ

Вот в основном чистое, основанное на атрибутах решение проблемы с несколькими кнопками отправки, основанное на публикации и комментариях от Мартена Баллиау .

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

628
29.10.2019 08:53:35
Я нашел это решение счастливым браком других методов, используемых. Работает отлично и не влияет на локализацию.
trevorc 29.11.2011 22:33:21
Отличное решение !! Намного полезнее, чем ответы с самыми высокими оценками
Sasha 16.02.2012 17:23:17
Проблема с этим подходом состоит в том, что если вы попытаетесь return View(viewmodel)в случае, когда в вашей модели есть ошибки, она попытается вернуть вызванное представление Sendили в зависимости от того, как называется ваш аргумент.
Shoe 17.10.2013 16:03:49
@Shoe - только что нашли похожую вещь. Убедитесь, что вы явно указали имя представления, которое будет возвращено, если вы используете этот метод:return View("Index", viewModel)
ajbeaven 27.11.2013 21:08:20
просто информация, нам нужно добавить system.Reflection для MethodInfo
Vignesh Subramanian 1.04.2015 11:06:19

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

21
14.01.2009 12:07:05
Безусловно самое чистое и простое решение, которое я видел.
Jason Evans 10.02.2015 11:11:28

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

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

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

13
13.08.2010 12:39:59
Хотя это работает, но я думаю, что неправильно иметь два элемента с одинаковым именем.
Péter 5.07.2013 11:25:54
Это не обязательно неправильно. Это зависит от того, как вы используете входы. Вы можете иметь несколько элементов с одинаковым именем и ожидать получения нескольких данных (именно так работают радиокнопки и флажки). Но да, если вы используете этот метод, потому что вы делаете это «неправильно» ... Вот почему я ставлю «Вы могли», а не «Вы должны»: P
Ironicnet 30.08.2013 18:29:01

Вы можете проверить имя в действии, как было упомянуто, но вы можете подумать, действительно ли это хороший дизайн. Хорошая идея - рассмотреть ответственность за действие и не связывать этот дизайн слишком сильно с такими аспектами пользовательского интерфейса, как названия кнопок. Итак, рассмотрим использование 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") %>
121
14.01.2009 12:26:26
Это нормально, когда вам не нужны одинаковые данные формы для каждой кнопки отправки. Если вам нужны все данные в общей форме, то Дилан Битти - это то, что вам нужно. Есть ли более элегантный способ сделать это?
zidane 28.09.2009 09:30:30
Что касается визуального представления, как в этом случае кнопка «Отправить» рядом с кнопкой «Отмена»?
Kris-I 9.03.2011 04:49:12
Дилан: Хорошо, для кнопки отмены вам вообще не нужно отправлять данные, и это плохая практика - связывать контроллер с элементами пользовательского интерфейса. Однако, если вы можете сделать более или менее общую «команду», то я думаю, что это нормально, но я бы не стал связывать ее с «submitButton», так как это имя элемента пользовательского интерфейса.
Trevor de Koekkoek 16.03.2011 15:08:54
@ Kris: вы можете расположить свои кнопки с помощью CSS, и они все еще могут находиться в 2 разных разделах формы.
Trevor de Koekkoek 16.03.2011 15:10:34
шутки в сторону? это не пахнет ни для кого, кроме меня ?!
user156888 24.11.2011 11:48:21

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

<% 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());
}
468
3.11.2010 11:37:50
Жаль, что вы зависите от текста, отображаемого на кнопке, это довольно сложно с мультиязычным пользовательским интерфейсом
Omu 22.04.2010 11:52:54
Переключатель / регистр работает только с константами, поэтому в локализованной версии нельзя использовать переключатель / регистр. Вам нужно переключиться, если еще или какой-либо другой способ отправки.
mlibby 1.11.2010 20:58:48
вы должны использовать <button type = "submit" вместо <input type, потому что значение типа <button не является текстом;). Тогда у вас может быть что-то вроде этого: <button name = "mySubmitButton" type = "submit" value = "keyValue"> YourButtonText </ button>
J4N 29.05.2012 12:32:30
Как это будет работать с передачей модели действию, а не просто значением отправки?
bizzehdee 7.08.2013 07:56:10
Будьте осторожны, чтобы не называть свои кнопки "action", если вы используете jQuery. Это вызывает конфликт внутри библиотеки, который нарушает действие URL.
HotN 14.10.2014 21:20:17

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

Если у вас есть более одной кнопки, вы можете различить их, дав каждой кнопке имя:

<input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />

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

public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }

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

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }

Мне нравится этот метод, так как он не опирается на свойство value кнопок отправки, которое с большей вероятностью изменится, чем назначенные имена, и не требует включения javascript.

Смотрите: http://forums.asp.net/p/1369617/2865166.aspx#2865166

98
21.01.2009 16:51:12
Если кто-то сталкивается с этим старым вопросом, это самый чистый ответ, если вы не хотите использовать элементы HTML5 <button>. Если вы не возражаете против HTML5, используйте <button> с атрибутом value.
Kugel 12.06.2013 01:28:40
Как бы вы это сделали, если создали ajax-вызов в этой форме. Похоже, что form.serialize () не отвечает за отправку имени кнопки.
mko 15.09.2014 14:15:52
@ Кугель прав, это самый чистый ответ. Спасибо
Arif YILMAZ 31.10.2016 12:42:53

Дэвид Финдли (David Findley) пишет о 3 различных вариантах для этого в своем блоге ASP.Net.

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

7
26.06.2009 09:35:26

Только что написал пост об этом: Несколько кнопок отправки с 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(…) {
        //…
    } 
}

Как видите, атрибут вообще не требует указывать что-либо. Кроме того, названия кнопок переводятся непосредственно в названия методов. Кроме того (я не пробовал этого), они также должны работать как обычные действия, так что вы можете публиковать сообщения на любом из них напрямую.

45
18.07.2013 03:05:38
Прекрасный! Я думаю, что это самое элегантное решение. Это устраняет значение этого submitтега из рассмотрения, который является идеальным , поскольку он является атрибутом чистого пользовательского интерфейса , который не должен иметь никакого отношения к потоку управления. Вместо этого уникальный nameатрибут каждого submitтега преобразуется непосредственно в метод дискретного действия на вашем контроллере.
Kirk Woll 26.10.2011 04:29:31
+1 Для меня это, безусловно, лучшее решение этой проблемы. С тех пор как я это реализовал, я заметил, что через HttpParamActionAttribut проходит много трафика, но по сравнению со всеми другими вещами, которые Asp.Net MVC должен делать при обработке запроса, это вполне приемлемо. Чтобы взломать только то, что мне нужно сделать, это поместить пустое «Действие» с именем в моем контроллере, чтобы Resharper не предупредил меня, что действие «Действие» не существует. Большое спасибо!
Samuel 18.01.2013 18:39:35
Я рассмотрел все решения и также согласен, что это хорошее элегантное и простое решение. Замечательно, что нет никаких условных операторов и надежно, где вы можете определить новое действие контроллера, когда у вас есть новая кнопка. Называется мой класс MultiButtonActionHandler FYI ;-)
ejhost 21.04.2015 19:30:18

Я бы предложил заинтересованным сторонам взглянуть на решение Мартена Баллиау . Я думаю, что это очень элегантно.

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

35
16.02.2017 00:33:01
Это решение, которое мы используем сейчас, и оно очень аккуратное. Это только MVC 2?
Simon Keep 2.11.2010 15:30:17
Это прекрасно! Я не видел этого раньше! Хотя я согласен с тем, что вы, возможно, захотите изменить дизайн любого решения, в котором используется несколько отправок, чтобы использовать только одну кнопку, я нахожусь в таком положении, что у меня возникают проблемы, и я должен это сделать. Этот ответ должен был победить!
Rikon 30.09.2011 14:19:00
Это отличное решение. Очень чисто
Arnej65 24.10.2011 13:42:02
Опробовал этот подход и не смог заставить его работать в MVC3. Вариант # 1 получателя голосов работал на меня.
Scott Lawrence 3.10.2012 19:36:51
Коротко и сладко .. но не для mvc 3+
Piotr Kula 18.07.2013 20:23:32

Это техника, которую я бы использовал, и пока не вижу ее здесь. Ссылка (опубликованная Saajid Ismail), которая вдохновляет это решение, является 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;
         }
    }
}
7
1.11.2010 21:20:29
Похоже, решение Ironicnet предоставлено.
Kris van der Mast 2.11.2010 15:02:27
Конечно, похоже, но это показывает и локализацию, и код контроллера, чего я не видел в этом потоке. Я нашел эту ветку, когда искал, как это сделать, и хотел задокументировать, что я придумал для всех, кто может быть в той же лодке.
mlibby 3.11.2010 11:56:43
На самом деле, это не то же самое, что Ironicnet. Он использует <input>элементы. Я использую <button>, что требуется, чтобы сделать локализацию без атрибутов значения переменной.
mlibby 3.11.2010 11:59:23

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

Вот 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_и извлекает команду после. Поскольку я абстрагируюсь от логики определения «команды», вы можете переключаться между кнопками image + text на клиенте, не меняя код на стороне сервера.

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".

6
19.02.2011 01:52:17
Мне нравится проверять имя как альтернативу, потому что вы не всегда можете проверить значение, например. у вас есть список элементов, и у каждого есть кнопка «Удалить».
Max 26.08.2011 11:09:00

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

<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();
}
-1
20.11.2012 22:02:56
В будущем вам будет полезно объяснить ваш код. Спасибо!
user1131435 16.03.2014 07:12:03

Мой подход 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')" >
3
19.10.2011 15:19:54

Если у вас нет ограничений на использование 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

10
8.11.2011 10:51:02

это лучший способ, который я нашел:

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

Наслаждайтесь несколькими кнопками отправки без запаха в будущем.

благодарю вас

5
28.10.2013 10:57:58
Ссылка на данный момент не работает, это самая близкая заархивированная версия, которую я смог найти: web.archive.org/web/20110706230408/http://blogs.sonatribe.com/…an
Ian Kemp 25.10.2013 15:09:03
Привет, Ян - спасибо, что выкопали это
user156888 28.10.2013 10:57:43

Вот что работает лучше всего для меня:

<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();
}
11
22.12.2011 00:46:25
Я получаю нулевое значение для onDelete и onSave в методе контроллера. Ты знаешь почему?
Diganta Kumar 24.01.2013 02:30:54
Любой из них не будет нулевым, если вы нажмете соответствующую кнопку. На какую кнопку вы нажимаете, чтобы получить ноль?
Sergey 8.07.2013 17:50:23

Моим решением было использовать 2 панели asp:

<asp:Panel ID=”..” DefaultButton=”ID_OF_SHIPPING_SUBMIT_BUTTON”….></asp:Panel>

-3
9.02.2012 17:43:36

Этот скрипт позволяет указать атрибут data-form-action, который будет работать как атрибут формирования HTML5 во всех браузерах (ненавязчиво):

$(document).on('click', '[type="submit"][data-form-action]', function(event) {
    var $this = $(this),
    var formAction = $this.attr('data-form-action'),
    $form = $($this.closest('form'));
    $form.attr('action', formAction);             
});

Форма, содержащая кнопку, будет размещена по URL-адресу, указанному в атрибуте data-form-action:

<button type="submit" data-form-action="different/url">Submit</button>   

Это требует jQuery 1.7. Для предыдущих версий вы должны использовать live()вместо on().

7
16.05.2013 12:16:50

Для каждой кнопки отправки просто добавьте:

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});
3
24.07.2012 17:23:39

Я попытался объединить все решения и создал атрибут [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);
}

Обратите внимание, как имя кнопки совпадает с именем метода действия. В статье также описано, как иметь кнопки со значениями и кнопки с индексами.

5
26.09.2012 16:34:26

У меня недостаточно представителей, чтобы комментировать в правильном месте, но я потратил на это целый день, поэтому хочу поделиться.

При попытке реализовать решение «MultipleButtonAttribute» ValueProvider.GetValue(keyValue)будет возвращаться неправильно null.

Оказалось, что я ссылался на System.Web.MVC версии 3.0, когда она должна была быть 4.0 (другие сборки - 4.0). Я не знаю, почему мой проект не обновился правильно, и у меня не было других очевидных проблем.

Так что, если ваш ActionNameSelectorAttributeне работает ... проверьте это.

6
14.12.2012 16:19:47
//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();
        }
5
26.02.2013 05:33:10
Возможно, вы этого не поняли, но этот же ответ уже был опубликован довольно часто на этот вопрос.
Andrew Barber 26.02.2013 05:39:39
Кроме того, вы, кажется, публикуете ответы, которые содержат только код, без объяснения причин. Не могли бы вы добавить какой-нибудь рассказ, чтобы объяснить, почему код работает, и что делает его ответом на вопрос? Это было бы очень полезно для человека, задающего вопрос, и для всех, кто придет.
Andrew Barber 26.02.2013 05:41:39
Конечно, работает нормально. Но этот ответ уже был дан другими , давным-давно. И они включали объяснения того, почему это работает тоже.
Andrew Barber 26.02.2013 05:49:51

На основании ответа 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.

3
26.09.2013 05:35:04

Модифицированная версия 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" />
}
4
17.10.2013 18:25:50

Что мне не нравится в 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" />
12
5.12.2014 17:56:02

Если ваш браузер поддерживает формирование атрибутов для кнопок ввода (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") />

}
9
27.02.2014 15:44:12
Посмотрите на мой ответ ниже, он не зависит от черновиков спецификаций. Ваш ответ дает возможность иметь разные URL-адреса действий, а мои нет.
Tom Hofman 30.04.2014 12:10:50

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

    }

}
11
9.01.2015 09:42:01
Это решение, которое мы решили использовать для простого веб-приложения, где нам нужна функциональность ASP.NET WebForms, но в MVC.
BrandonG 14.09.2016 20:17:39

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 = "Отклонить"> Отклонить

}

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

}
-4
5.03.2015 00:57:13

При использовании 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();
}
0
7.05.2015 18:42:52

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

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

public class SubmitButtonSelector : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
        {
            // Try to find out if the name exists in the data sent from form
var value = controllerContext.Controller.ValueProvider.GetValue(Name);
            if (value != null)
            {
                return true;
            }
            return false;

        }
    }

Основное назначение вышеуказанной функции - в приведенном ниже коде. Коллекция «ValueProvider» содержит все данные, отправленные из формы. Поэтому он сначала ищет значение «Имя» и, если оно найдено в HTTP-запросе, возвращает значение «истина» или же возвращает «ложь».

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");
        }
}
9
21.05.2015 03:29:27