webentwicklung-frage-antwort-db.com.de

Wie gehen Sie mit mehreren Übergabeschaltflächen in ASP.NET MVC Framework um?

Gibt es eine einfache Möglichkeit, mehrere Übergabeschaltflächen in demselben Formular zu verarbeiten? Beispiel:

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

Haben Sie eine Idee, wie Sie dies in ASP.NET Framework Beta tun können? Alle Beispiele, nach denen ich gegoogelt habe, enthalten einzelne Schaltflächen.

710
Spoike

Hier ist eine meist saubere, auf Attributen basierende Lösung für das Problem mit mehreren Senden-Schaltflächen, die stark auf dem Beitrag und den Kommentaren von Maartin Balliauw basiert.

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

rasierer:

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

und Controller:

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

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

Update: Rasiermesserseiten scheint die gleiche Funktionalität von Anfang an zu bieten. Für Neuentwicklungen kann dies vorzuziehen sein.

607
mkozicki

Geben Sie Ihren Submit-Schaltflächen einen Namen und überprüfen Sie den übergebenen Wert in Ihrer Controller-Methode:

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

posten an

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

}

BEARBEITEN:

Isolieren Sie Ihre Nachrichten an einer anderen Stelle (z. B. Kompilieren einer Ressourcendatei zu einer stark typisierten Ressourcenklasse), um diesen Ansatz auf die Arbeit mit lokalisierten Sites zu erweitern.

Ändern Sie dann den Code so, dass er wie folgt funktioniert:

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

und dein controller sollte so aussehen:

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

Sie können den Namen in der Aktion überprüfen, wie bereits erwähnt, aber Sie könnten überlegen, ob dies ein gutes Design ist oder nicht. Es ist eine gute Idee, die Verantwortung der Aktion zu berücksichtigen und dieses Design nicht zu sehr mit UI-Aspekten wie Schaltflächennamen zu koppeln. Verwenden Sie also 2 Formulare und 2 Aktionen:

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

Im Fall von "Abbrechen" bearbeiten Sie das Formular normalerweise nur nicht und wechseln zu einer neuen URL. In diesem Fall brauchen Sie das Formular gar nicht einzureichen und brauchen nur einen Link:

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

Eilon schlägt vor, dass Sie es so machen können:

Wenn Sie mehr als eine Schaltfläche haben, können Sie diese unterscheiden, indem Sie jeder Schaltfläche einen Namen geben:

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

In Ihrer Controller-Aktionsmethode können Sie Parameter hinzufügen, die nach den Namen der HTML-Eingabe-Tags benannt sind:

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

Wenn ein Wert in einen dieser Parameter geschrieben wird, bedeutet dies, dass diese Schaltfläche angeklickt wurde. Der Webbrowser gibt nur einen Wert für die eine Schaltfläche bekannt, auf die geklickt wurde. Alle anderen Werte sind null.

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

Diese Methode gefällt mir, da sie nicht auf der value-Eigenschaft der Submit-Schaltflächen beruht, die sich mit größerer Wahrscheinlichkeit ändert als die zugewiesenen Namen, und für die keine Aktivierung von Javascript erforderlich ist

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

97
PabloBlamirez

Habe gerade einen Beitrag dazu geschrieben: Mehrere Submit-Buttons mit ASP.NET MVC :

Anstatt ActionMethodSelectorAttribute zu verwenden, verwende ich ActionNameSelectorAttribute, wodurch ich so tun kann, als wäre der Aktionsname so, wie ich es möchte. Glücklicherweise muss ich mit ActionNameSelectorAttribute nicht nur den Aktionsnamen angeben, sondern kann auch auswählen, ob die aktuelle Aktion der Anforderung entspricht.

Es gibt also meine Klasse (übrigens mag ich den Namen nicht so gerne):

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

Zur Verwendung definieren Sie einfach ein Formular wie dieses:

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

und Controller mit zwei Methoden

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

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

Wie Sie sehen, müssen Sie für das Attribut überhaupt nichts angeben. Außerdem werden die Namen der Schaltflächen direkt in die Methodennamen übersetzt. Außerdem (das habe ich noch nicht versucht) sollten diese Aktionen auch als normale Aktionen funktionieren, sodass Sie direkt auf eine der Aktionen posten können.

45
Andrey Shchekin

Ich würde Interessenten vorschlagen werfen Sie einen Blick auf die Lösung von Maarten Balliauw . Ich finde es sehr elegant.

Wenn der Link nicht mehr angezeigt wird, wird das Attribut MultiButton verwendet, das auf eine Controller-Aktion angewendet wird, um anzugeben, auf welche Schaltfläche sich diese Aktion beziehen soll.

35
Izmoto

es ist kurz und Suite:

Es wurde von Jeroen Dop beantwortet

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

und mache dies im Code behinde

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

Viel Glück.

33
Ali Golgol

Sie sollten in der Lage sein, die Schaltflächen zu benennen und ihnen einen Wert zu geben. Ordnen Sie dann diesen Namen der Aktion als Argument zu. Alternativ können Sie 2 separate Aktionslinks oder 2 Formulare verwenden.

21
Marc Gravell

Sie könnten schreiben:

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

Und dann in der Seite prüfen, ob der Name == "Senden" oder der Name == "Abbrechen" ...

13
Ironicnet

An ActionSelectName gefällt mir nicht, dass IsValidName für jede Aktionsmethode im Controller aufgerufen wird. Ich weiß nicht, warum es so funktioniert. Ich mag eine Lösung, bei der jede Schaltfläche einen anderen Namen hat, aber ich mag nicht, dass Sie so viele Parameter in der Aktionsmethode haben müssen wie Schaltflächen im Formular. Ich habe eine Aufzählung für alle Schaltflächentypen erstellt:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Anstelle von ActionSelectName verwende ich einen 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;
            }
        }
    }
}

Der Filter findet den Schaltflächennamen in den Formulardaten. Wenn der Schaltflächenname mit einem der in der Aufzählung definierten Schaltflächentypen übereinstimmt, findet er den Parameter ButtonType unter den Aktionsparametern:

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

und dann in Ansichten kann ich verwenden:

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

Folgendes funktioniert am besten für mich:

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

Wenn Ihr Browser die Attributformulierung für Eingabeschaltflächen unterstützt (IE 10+, andere Browser nicht sicher), sollte Folgendes funktionieren:

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

Wenn Sie keine Einschränkungen für die Verwendung von HTML 5 haben, können Sie das <button> -Tag mit dem formaction -Attribut verwenden:

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

Referenz: http://www.w3schools.com/html5/att_button_formaction.asp

9
Acaz Souza

Ich bin auch auf dieses 'Problem' gestoßen, habe aber eine ziemlich logische Lösung gefunden, indem ich das name -Attribut hinzugefügt habe. Ich konnte mich nicht erinnern, dieses Problem in anderen Sprachen gehabt zu haben.

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

  • ...
  • Wenn ein Formular mehr als eine Senden-Schaltfläche enthält, ist nur die aktivierte Senden-Schaltfläche erfolgreich.
  • ...

Dies bedeutet, dass die folgenden Attribute des Codes value geändert, lokalisiert und internationalisiert werden können, ohne dass zusätzliche Codeprüfungen für stark typisierte Ressourcendateien oder -konstanten erforderlich sind .

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

Auf der Empfängerseite müssten Sie nur überprüfen, ob einer Ihrer bekannten Übermittlungstypen nicht null ist.

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

    }

}
9
Tom Hofman

Es gibt drei Möglichkeiten, wie Sie das oben genannte Problem lösen können

  1. HTML Weg
  2. Jquery Weg
  3. "ActionNameSelectorAttribute" -Methode

Im Folgenden finden Sie ein Video, in dem alle drei Ansätze auf anschauliche Weise zusammengefasst sind.

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

HTML-Methode: -

In HTML müssen wir zwei Formulare erstellen und die Schaltfläche "Senden" in jedes der Formulare einfügen. Und die Aktion jedes Formulars verweist auf unterschiedliche/entsprechende Aktionen. Sie können den folgenden Code sehen, den das erste Formular für "Aktion1" bereitstellt, und das zweite Formular für "Aktion2", je nachdem, auf welche Schaltfläche "Senden" geklickt wird.

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

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

Ajax-Methode: -

Wenn Sie ein Ajax-Liebhaber sind, würde Sie diese zweite Option mehr begeistern. Auf Ajax-Art können wir zwei verschiedene Funktionen "Fun1" und "Fun1" erstellen, siehe folgenden Code. Diese Funktionen rufen Ajax mithilfe von JQUERY oder einem anderen Framework auf. Jede dieser Funktionen ist mit den "OnClick" -Ereignissen der Schaltfläche "Senden" verknüpft. Jede dieser Funktionen ruft die entsprechenden Aktionsnamen auf.

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

Verwenden von "ActionNameSelectorAttribute": -

Dies ist eine großartige und saubere Option. Das „ActionNameSelectorAttribute“ ist eine einfache Attributklasse, in der wir eine Entscheidungslogik schreiben können, die entscheidet, welche Aktion ausgeführt werden kann.

Als Erstes müssen wir in HTML den Senden-Schaltflächen die richtigen Namen zuweisen, um sie auf dem Server zu identifizieren.

Wie Sie sehen, haben wir die Schaltflächennamen mit "Speichern" und "Löschen" versehen. Sie können auch in der Aktion feststellen, dass wir gerade den Namen des Controllers "Kunde" und nicht einen bestimmten Aktionsnamen eingegeben haben. Wir erwarten, dass der Aktionsname von „ActionNameSelectorAttribute“ bestimmt wird.

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

Wenn Sie also auf die Schaltfläche "Senden" klicken, wird zuerst das Attribut "ActionNameSelector" aufgerufen, und je nachdem, welches Senden ausgelöst wird, wird die entsprechende Aktion aufgerufen.

enter image description here

Der erste Schritt besteht also darin, eine Klasse zu erstellen, die von der Klasse "ActionNameSelectorAttribute" erbt. In dieser Klasse haben wir eine einfache Eigenschaft "Name" erstellt.

Wir müssen auch die Funktion "IsValidName" überschreiben, die true oder flase zurückgibt. In dieser Funktion schreiben wir die Logik, ob eine Aktion ausgeführt werden muss oder nicht. Wenn diese Funktion also true zurückgibt, wird die Aktion ausgeführt oder nicht.

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;

        }
    }

Das Hauptherz der obigen Funktion befindet sich im folgenden Code. Die Auflistung "ValueProvider" enthält alle Daten, die aus dem Formular bereitgestellt wurden. Also sucht es zuerst den Wert "Name" und wenn er in der HTTP-Anforderung gefunden wird, gibt es "true" zurück oder "false".

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

Diese Attributklasse kann dann für die jeweilige Aktion dekoriert und der jeweilige Wert „Name“ angegeben werden. Wenn also der Submit diese Aktion trifft und der Name mit dem Namen der HTML-Submit-Schaltfläche übereinstimmt, führt er die Aktion weiter aus oder tut dies nicht.

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

Mit diesem Skript können Sie ein Datenformular-Aktionsattribut angeben, das in allen Browsern (auf unauffällige Weise) als HTML5-Formatierungsattribut fungiert:

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

Das Formular mit der Schaltfläche wird an die URL gesendet, die im Datenformular-Aktionsattribut angegeben ist:

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

Dies erfordert jQuery 1.7. Für frühere Versionen sollten Sie live() anstelle von on() verwenden.

7
Jay Douglass

David Findley schreibt in seinem ASP.Net-Weblog über drei verschiedene Optionen, die Sie dazu haben.

Lesen Sie den Artikel mehrere Schaltflächen in derselben Form , um seine Lösungen sowie die Vor- und Nachteile der einzelnen zu sehen. IMHO bietet er eine sehr elegante Lösung, die Attribute verwendet, mit denen Sie Ihre Aktion dekorieren.

7
Saajid Ismail

Dies ist die Technik, die ich verwenden würde und ich sehe es hier noch nicht. Der Link (gepostet von Saajid Ismail), der diese Lösung inspiriert, lautet http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the -same-form.aspx ). Es passt Dylan Beatties Antwort an, um die Lokalisierung ohne Probleme durchzuführen.

In der Ansicht:

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

Im Controller:

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

Hier ist eine Erweiterungsmethode, die ich geschrieben habe, um mit mehreren Bild- und/oder Textschaltflächen umzugehen.

Hier ist der HTML-Code für eine Bildschaltfläche:

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

oder für einen Text Submit Button:

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

Hier ist die Erweiterungsmethode, die Sie vom Controller mit form.GetSubmitButtonName() aufrufen. Für Bildschaltflächen sucht es mit .x nach einem Formularparameter (der angibt, dass auf eine Bildschaltfläche geklickt wurde) und extrahiert den Namen. Bei normalen Tasten input wird nach einem Namen gesucht, der mit Submit_ beginnt, und anschließend der Befehl extrahiert. Da ich die Logik der Bestimmung des "Befehls" abstrahiere, können Sie auf dem Client zwischen Bild- und Textschaltflächen wechseln, ohne den serverseitigen Code zu ändern.

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

Hinweis: Bei Textschaltflächen muss dem Namen Submit_ vorangestellt werden. Ich bevorzuge diesen Weg, weil Sie den Textwert (den Anzeigewert) ändern können, ohne den Code ändern zu müssen. Im Gegensatz zu SELECT Elementen hat eine INPUT Schaltfläche nur einen 'Wert' und kein separates 'Text'-Attribut. Meine Schaltflächen sagen unter verschiedenen Kontexten unterschiedliche Dinge aus - sind jedoch demselben Befehl zugeordnet. Ich ziehe es sehr vor, den Namen auf diese Weise zu extrahieren, als für == "Add to cart" codieren zu müssen.

6
Simon_Weaver

Ich habe nicht genug Repräsentanten, um an der richtigen Stelle zu kommentieren, aber ich habe den ganzen Tag damit verbracht, dies zu teilen.

Beim Versuch, die Lösung "MultipleButtonAttribute" zu implementieren, wurde ValueProvider.GetValue(keyValue) fälschlicherweise als null zurückgegeben.

Es stellte sich heraus, dass ich auf System.Web.MVC Version 3.0 verwies, als es 4.0 hätte sein sollen (andere Assemblys sind 4.0). Ich weiß nicht, warum mein Projekt nicht korrekt aktualisiert wurde und ich keine anderen offensichtlichen Probleme hatte.

Also, wenn Ihr ActionNameSelectorAttribute nicht funktioniert ... überprüfen Sie das.

6
HeatherD

Ich komme ziemlich spät zur Party, aber hier geht es weiter ... Meine Implementierung ist von @mkozicki entlehnt, erfordert aber weniger fest codierte Zeichenfolgen, um falsch zu werden. Framework 4.5+ erforderlich . Im Wesentlichen sollte der Name der Controller-Methode der Schlüssel zum Routing sein.

Markup . Der Tastenname muss mit "action:[controllerMethodName]" eingegeben werden

(Beachten Sie die Verwendung der API C # 6 nameof , die eine typspezifische Referenz auf den Namen der Controller-Methode enthält, die Sie aufrufen möchten.

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

Controller :

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

Attribut Magie . Beachten Sie die Verwendung von CallerMemberName goodness.

[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;
    }
}
6
Aaron Hudon

das ist der beste Weg, den ich gefunden habe:

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

Hier ist der Code:

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

Genießen Sie eine Zukunft ohne Code-Geruch und mit mehreren Submit-Buttons.

dankeschön

5
user156888
//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
SHAURAJ SINGH

Ich habe versucht, eine Synthese aller Lösungen zu erstellen, und ein [ButtenHandler] -Attribut erstellt, mit dem mehrere Schaltflächen in einem Formular problemlos verarbeitet werden können.

Ich habe es in CodeProject beschrieben Mehrfach parametrisierte (lokalisierbare) Formularschaltflächen in ASP.NET MVC .

So behandeln Sie den einfachen Fall dieser Schaltfläche:

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

Sie haben so etwas wie die folgende Aktionsmethode:

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

Beachten Sie, wie der Name der Schaltfläche mit dem Namen der Aktionsmethode übereinstimmt. Der Artikel beschreibt auch, wie Schaltflächen mit Werten und Schaltflächen mit Indizes erstellt werden.

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

    }
5
Mahendra

Geänderte Version der HttpParamActionAttribute -Methode, jedoch mit einer Fehlerbehebung, um bei abgelaufenen/ungültigen Sitzungs-Postbacks keinen Fehler zu verursachen. Um festzustellen, ob dies ein Problem mit Ihrer aktuellen Site ist, öffnen Sie das Formular in einem Fenster, und klicken Sie kurz vor dem Klicken auf Save oder Publish auf ein doppeltes Fenster, und melden Sie sich ab. Kehren Sie jetzt zu Ihrem ersten Fenster zurück und versuchen Sie, Ihr Formular über eine der beiden Schaltflächen zu senden. Für mich ist ein Fehler aufgetreten, sodass diese Änderung das Problem für mich löst. Der Kürze halber lasse ich ein paar Sachen weg, aber Sie sollten die Idee haben. Die Schlüsselteile sind das Einfügen von ActionName in das Attribut und das Sicherstellen, dass der übergebene Name der Name der Ansicht ist, in der das Formular angezeigt wird

Attributklasse

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

Controller

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

Ansicht

@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
Nick Albrecht

Mein JQuery-Ansatz mit einer Erweiterungsmethode:

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

Du kannst es so benutzen:

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

Und es rendert so:

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

Basierend auf der Antwort von mkozicki habe ich eine etwas andere Lösung gefunden. Ich benutze immer noch ActionNameSelectorAttribute, aber ich musste mit den beiden Schaltflächen 'Speichern' und 'Synchronisieren' umgehen. Sie machen fast dasselbe, also wollte ich keine zwei Aktionen haben.

Attribut:

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

Ansicht

<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"];

Ich möchte auch darauf hinweisen, dass wenn Aktionen verschiedene Dinge tun, ich wahrscheinlich mkozicki post folgen würde.

3
Petr J

Fügen Sie für jede Senden-Schaltfläche einfach Folgendes hinzu:

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

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

});
3
mishap

Ich habe eine ActionButton -Methode für HtmlHelper erstellt. Es wird eine normale Eingabeschaltfläche mit etwas Javascript im OnClick-Ereignis generiert, die das Formular an den angegebenen Controller/die angegebene Aktion sendet.

Du benutzt den Helfer so

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

dadurch wird der folgende HTML-Code generiert

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

Hier ist der Erweiterungsmethodencode:

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 # (Der C # -Code wird gerade aus der VB -DLL dekompiliert, damit er etwas verschönert wird ... aber die Zeit ist so kurz :-))

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

Diese Methoden verfügen über verschiedene Parameter. Zur Vereinfachung der Verwendung können Sie jedoch eine Überladung erstellen, die nur die von Ihnen benötigten Parameter verwendet.

1
Max

Wenn Sie Ajax-Formulare verwenden, können Sie ActionLinks mit POST HttpMethod verwenden und das Formular im AjaxOptions.OnBegin-Ereignis serialisieren.

Angenommen, Sie haben zwei Aktionen, InsertAction und 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
jBelanger

Verwenden Sie einen benutzerdefinierten Helfer (erstellen Sie eine Datei "Helpers.cshtml" im Ordner "App_Code" im Stammverzeichnis Ihres Projekts) mit Javascript, um das Attribut "action" des Formulars bei einem "onclick" -Ereignis neu zu schreiben und dann zu übermitteln es.

Der Helfer könnte sein:

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

Und dann benutze es als:

@Helpers.SubmitButton("Text for 1st button","ControllerForButton1","ActionForButton1")
@Helpers.SubmitButton("Text for 2nd button","ControllerForButton2","ActionForButton2")
...

In deinem Formular.

0
galmeida