Pergunta

Existe alguma maneira fácil de múltipla alça enviar botões da mesma forma? Exemplo:

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

Qualquer idéia de como fazer isso em ASP.NET Framework Beta? Todos os exemplos que eu pesquisei para ter botões individuais neles.

Foi útil?

Solução

Aqui é uma solução baseada em atributos principalmente limpo para o múltiplo de submissão botão fortemente baseada no post e comentários de Maartin 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;
    }
}

navalha:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Cancel" name="action:Cancel" />
</form>

e controlador:

[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }

Atualização: páginas Navalha olhares para fornecer a mesma funcionalidade fora da caixa. Para novos desenvolvimentos, pode ser preferível.

Outras dicas

Dê seu enviar botões um nome e, em seguida, inspecionar o valor enviado em seu método de controlador:

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

postagem para

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

}

EDIT:

Para estender esta abordagem para trabalhar com sites localizados, isolar suas mensagens em outro lugar (por exemplo, a compilação de um arquivo de recurso para uma classe de recurso fortemente tipado)

Em seguida, modifique o código para que ele funciona como:

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

e seu controlador deve ficar assim:

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

Você pode verificar o nome na ação como já foi mencionado, mas você pode considerar se este é ou não um bom design. É uma boa ideia a considerar a responsabilidade da ação e não par este projeto muito para os aspectos de interface do usuário, como nomes de botões. Então considere usar 2 formas e 2 acções:

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

Além disso, no caso de "Cancelar", você são geralmente apenas não processar o formulário e está indo para um novo URL. Neste caso, você não precisa enviar o formulário em tudo e só precisa de um link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>

Eilon sugere que você pode fazê-lo como este:

Se você tem mais de um botão você pode distinguir entre eles, dando cada botão um nome:

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

No seu método de ação do controlador você pode adicionar parâmetros nomeados após a HTML nomes de tags de entrada:

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

Se qualquer valor é enviada para um dos estes parâmetros, o que significa que botão foi a única que obteve clicado. O navegador web só vai postar um valor para o um botão que foi clicado. Todos os outros valores serão nulos.

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

Eu gosto deste método, uma vez que não se baseia na propriedade valor da botões que é mais provável que a mudança do que os nomes atribuídos e não requer javascript submeter-se a ser habilitado

Veja: http://forums.asp.net/p/1369617/2865166.aspx#2865166

Apenas escreveu um post sobre isso: Multiple enviar botões com ASP.NET MVC :

Basicamente, em vez de usar ActionMethodSelectorAttribute, estou usando ActionNameSelectorAttribute, o que me permite fingir que o nome da ação é o que eu quiser que ele seja. Felizmente, ActionNameSelectorAttribute não apenas faz-me especificar nome da ação, em vez disso, pode escolher se a ação atual corresponde a pedido.

Portanto, não é a minha classe (btw eu não sou muito apreciador do nome):

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

Para usar apenas definir um formulário como este:

<% using (Html.BeginForm("Action", "Post")) { %>
  <!— …form fields… -->
  <input type="submit" name="saveDraft" value="Save Draft" />
  <input type="submit" name="publish" value="Publish" />
<% } %> 

e controlador com dois métodos

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}

Como você pode ver, o atributo não requer que você especifique nada. Além disso, o nome dos botões são traduzidos diretamente para os nomes de métodos. Além disso (eu não tentei isso) estes devem trabalhar como ações normais, bem, então você pode enviar a qualquer um deles diretamente.

Eu sugeriria partes interessadas ter um olhar de Maarten Balliauw solução . Eu acho que é muito elegante.

No caso dos dissapears ligação, ele está usando o atributo MultiButton aplicada a uma ação do controlador para indicar qual botão clique que a ação deve se relacionar.

é curto e suite:

Ele foi respondido por Jeroen Dop

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />

e fazer assim em behinde código

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}

Boa sorte.

Você deve ser capaz de citar os botões e dar-lhes um valor; em seguida, mapear esse nome como um argumento para a ação. Alternativamente, usam-2 acção ligações separadas ou 2 formas.

Você poderia escrever:

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

E, em seguida, na verificação de página se o nome == "Enviar" ou nome == "Cancelar" ...

Algo que eu não gosto sobre ActionSelectName é que IsValidName é chamado para cada método de ação no controlador; Eu não sei por que ela funciona dessa maneira. Eu gosto de uma solução onde cada botão tem um nome diferente com base no que ele faz, mas eu não gosto do fato de que você tem que ter o maior número de parâmetros no método de ação como botões no formulário. Eu criei uma enumeração para todos os tipos de botão:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Em vez de ActionSelectName, eu uso um 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;
            }
        }
    }
}

O filtro vai encontrar o nome do botão nos dados do formulário e se o nome do botão corresponde a qualquer dos tipos de botão definido na enumeração, ele vai encontrar o parâmetro ButtonType entre os parâmetros de ação:

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}

e, em seguida, em vista, eu posso usar:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />

Aqui está o que funciona melhor para mim:

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

Se você não tem restrições sobre o uso de HTML 5, você pode usar a tag <button> com Atributo 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>

Referência: http://www.w3schools.com/html5/att_button_formaction.asp

Se o seu navegador suporta a formaction atributo para botões de entrada (IE 10+, não tenho certeza sobre outros navegadores), em seguida, o seguinte deve funcionar:

@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") />

}

Eu deparei com este 'problema' tão bem, mas encontrou uma solução bastante lógica, adicionando o atributo name. Eu não conseguia se lembrar de ter este problema em outros idiomas.

http://www.w3.org/ TR / html401 / Interact / Forms.html # h-17.13.2

  • ...
  • Se um formulário contiver mais de um botão enviar, apenas o activado enviar botão é bem sucedido.
  • ...

Significado os seguintes atributos value código pode ser alterado, localizada, internacionalizada sem a necessidade para o código extra de verificação de arquivos ou constantes de recursos fortemente tipados.

<% 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(); %>`

no fim de recepção você só precisa verificar se qualquer um dos seus conhecidos enviar tipos não é 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

    }

}

Há três maneiras pelas quais você pode resolver o problema acima

  1. maneira HTML
  2. Jquery maneira
  3. “ActionNameSelectorAttribute” maneira

Abaixo está um vídeo que resume todas as três abordagens de uma forma demonstrativa.

https://www.facebook.com/shivprasad.koirala/ videos / vb.100002224977742 / 809335512483940

modo HTML: -

No caminho HTML precisamos criar duas formas e coloque o botão “Enviar” dentro de cada uma das formas. E a ação de todas as formas irá apontar para diferentes respectivas ações /. Você pode ver o código abaixo a primeira forma é postar a “Action1” e a segunda forma irá publicar a “Action2” dependendo de qual botão “Enviar” é clicado.

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>

forma Ajax: -

No caso de você é um amante Ajax esta segunda opção seria excitá-lo mais. No caminho Ajax podemos criar duas funções diferentes “fun1” e “fun1”, veja o código abaixo. Essas funções irão fazer chamadas Ajax usando JQUERY ou qualquer outra estrutura. Cada uma destas funções são binded com eventos “onclick” no botão “enviar” do. Cada um destes função de fazer chamadas para respectivos nomes de ação.

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

Usando o “ActionNameSelectorAttribute”: -

Este é um grande e uma opção limpa. O “ActionNameSelectorAttribute” é uma classe atributo simples, onde podemos escrever tomada de decisão lógica que vai decidir qual ação pode ser executada.

Assim, a primeira coisa é em HTML é preciso colocar adequada nome de aos botões enviar para identificá-los no servidor.

Você pode ver que colocamos “Save” e “Delete” para os nomes dos botões. Além disso, você pode notar na ação que acabamos de colocar controlador de nome “Cliente” e não um nome de determinada ação. Esperamos que o nome da ação será decidir por “ActionNameSelectorAttribute”.

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>

Assim, quando a enviar botão é clicado, ele primeiro atinge o atributo “ActionNameSelector” e, em seguida, dependendo do que enviar é disparado ele invoca a ação apropriada.

enter descrição da imagem aqui

Assim, o primeiro passo é criar uma classe que herda de classe “ActionNameSelectorAttribute”. Nesta classe, criamos uma simples propriedade “Name”.

Nós também precisamos substituir a função “IsValidName”, que retorna verdadeiro ou Falso. Esta função é onde nós escrevemos a lógica se uma ação tem de ser executado ou não. Então, se esta função retorna verdadeiro então a ação é executada, ou então ele não é.

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;

        }
    }

A principal centro da função acima é no código abaixo. A coleção “ValueProvider” tem todos os dados que foram publicadas a partir do formulário. Assim, ele primeiro procura o valor “Nome” e se a sua encontrados no pedido HTTP que retorna verdadeiro ou então ele retorna false.

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;

Esta classe atributo pode, em seguida, decorado na respectiva acção eo respectivo valor “Nome” pode ser fornecido. Portanto, se a enviar é bater essa ação e se os resultados nome do HTML enviar nome do botão que, em seguida, executa a ação ainda mais, ou então não.

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}

David Findley escreve cerca de 3 opções diferentes que você tem para fazer isso, em sua ASP.Net weblog.

Leia o artigo vários botões na mesma forma ver suas soluções, e as vantagens e desvantagens de cada um. IMHO ele fornece uma solução muito elegante, que faz uso de atributos que você decorar a sua ação com.

Esta é a técnica que eu uso e eu não vejo isso aqui ainda. O link (postado por Saajid Ismail ) Que inspira esta solução é http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx ). Ele se adapta a resposta de Dylan Beattie fazer localização sem problemas.

No Ver:

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

No Controlador:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}

Este script permite especificar um atributo-formaction dados que irá funcionar como o atributo HTML5 formaction em todos os navegadores (de uma forma discreta):

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

O formulário que contém o botão será enviada para o URL especificado no atributo-form-action de dados:

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

Isto requer jQuery 1.7. Para versões anteriores, você deve usar live() vez de on().

Aqui está um método de extensão Eu escrevi para lidar com imagem múltipla e / ou botões de texto.

Aqui está o HTML para um botão de imagem:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">

ou para um texto botão enviar:

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

Aqui está o método de extensão que você chamar a partir do controlador com form.GetSubmitButtonName(). Para botões de imagem ele procura por um parâmetro de formulário com .x (que indica um botão de imagem foi clicado) e extrai o nome. Para botões regulares input ele procura por um começo nome com Submit_ e extrai o comando depois. Porque eu estou abstraindo a lógica de determinar o 'comando' você pode alternar entre imagem + botões de texto no cliente, sem alterar o código do lado do servidor.

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

Nota: Para botões de texto você tem que prefixar o nome com Submit_. Eu prefiro desta forma becuase significa que você pode alterar o valor de texto (visualização) sem ter que mudar o código. Ao contrário de elementos SELECT, um botão INPUT tem apenas um 'valor' e nenhum atributo 'text' separado. Meus botões dizem coisas diferentes em contextos diferentes - mas mapear para o mesmo 'comando'. Eu prefiro muito mais extrair o nome desta forma do que ter de código para == "Add to cart".

Eu não tenho rep suficiente para comentário no lugar correto, mas eu passei o dia todo neste assim deseja compartilhar.

Ao tentar implementar o "MultipleButtonAttribute" solução ValueProvider.GetValue(keyValue) incorretamente vêm null de volta.

Acontece que eu estava fazendo referência System.Web.Mvc versão 3.0, quando deveria ter sido 4,0 (outros conjuntos são 4.0). Eu não sei por que meu projeto não atualizar corretamente e eu não tinha outros problemas óbvios.

Portanto, se seu ActionNameSelectorAttribute não está funcionando ... verificar isso.

Eu sou muito atrasado para a festa, mas aqui vai ... Meus toma emprestado de implementação de @mkozicki mas requer cordas menos codificado para errar. Framework 4.5 + necessário . Essencialmente, o nome do método controlador deve ser a chave para o roteamento.

Markup . O nome do botão devem ser digitados com "action:[controllerMethodName]"

(Observe o uso do nameof API C # 6, proporcionando referência de tipo específico para o nome do método de controlador que você deseja executar.

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

Controlador :

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

Atributo Magia . Observe o uso da CallerMemberName bondade.

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

Eu tentei fazer uma síntese de todas as soluções e criou um atributo [ButtenHandler] que torna mais fácil de lidar com vários botões em um formulário.

Eu descrevi-o em CodeProject parametrizado múltipla ( localizável) botões de formulário em ASP.NET MVC .

Para lidar com o simples caso de este botão:

<button type="submit" name="AddDepartment">Add Department</button>

Você vai ter algo parecido com o seguinte método de ação:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

Observe como o nome do botão corresponde ao nome do método de ação. O artigo também descreve como têm botões com valores e botões com índices.

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

Esta é a melhor maneira que eu encontrei:

http: // iwayneo. blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

Aqui está o código:

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

Desfrute de um code-cheiro-menos de multi submeter futuro botão.

obrigado

[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>

    }

Versão modificada do método HttpParamActionAttribute mas com uma correção de bug para não causar um erro em postbacks sessão expirada / inválido. Para ver se este é um problema com o seu site atual, abra o seu formulário em uma janela e pouco antes de ir para clicar Save ou Publish, abra uma janela duplicada, e sair. Agora volte para a primeira janela e tentar enviar seu formulário usando o botão. Para mim, eu tenho um erro para que essa alteração resolve esse problema para mim. I omitir um monte de coisas em prol da brevidade, mas você deve ficar com a ideia. As peças-chave são a inclusão de ActionName no atributo e certificando-se o nome passado é o nome da exibição que mostra a forma

Atributo Class

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

Controlador

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

Ver

@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" />
}

abordagem Meu JQuery usando um método de extensão:

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

Você pode usá-lo como este:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

E torna assim:

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >

Para cada botão enviar basta adicionar:

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

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

});

Com base mkozicki responder eu chegar a uma solução diferente bit. Eu ainda uso ActionNameSelectorAttribute Mas eu precisava para lidar com dois botões 'Salvar' e 'Sync'. Eles fazem quase o mesmo que eu não queria ter duas ações.

atributo :

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

Ver

<input type="submit" value="Save" name="Save" />
<input type="submit" value="Save and Sync" name="Sync" />

controller

 [MultipleButtonAction("Save", "Sync")]
 public ActionResult Sync(OrgSynchronizationEditModel model)
 {
     var btn = this.RouteData.Values["ButtonName"];

Também quero salientar que se as ações fazem coisas diferentes I provavelmente siga pós mkozicki.

Eu criei um ActionButton método para o HtmlHelper . Ele irá gerar normal botão de entrada com um pouco de javascript na OnClick evento que irá enviar o formulário para o controle / ação especificada.

Você usa o ajudante assim

@Html.ActionButton("MyControllerName", "MyActionName", "button text")

isso irá gerar o seguinte HTML

<input type="button" value="button text" onclick="this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();">

Aqui está o código método de extensão:

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 # (o código C # é apenas compilado a partir do VB DLL, para que ele possa obter algum embelezamento ... mas o tempo é tão curto: -))

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

Estes métodos têm vários parâmetros, mas para a facilidade de uso que você pode criar alguma sobrecarga que levar apenas os parâmetros que você precisa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top