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

733

Gibt es eine einfache Möglichkeit, mehrere Senden-Schaltflächen aus demselben Formular zu verarbeiten? Zum Beispiel:

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

Irgendeine Idee, wie dies in ASP.NET Framework Beta gemacht wird? Alle Beispiele, nach denen ich gegoogelt habe, enthalten einzelne Schaltflächen.

Spoike
quelle
6
Erwähnenswert ist, dass es ab ASP.NET Core viel einfachere Lösungen gibt als die hier aufgeführten.
Steven Jeuris
Dieses Tutorial könnte helfen: Senden eines Formulars an verschiedene Aktionsmethoden in ASP.NET MVC
Hooman Bahreini

Antworten:

629

Hier ist eine größtenteils saubere, auf Attributen basierende Lösung für das Problem mit mehreren Senden- Schaltflächen, die stark auf dem Beitrag und den Kommentaren von Maarten 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 bieten sofort die gleiche Funktionalität. Für Neuentwicklungen kann dies vorzuziehen sein.

mkozicki
quelle
3
Ich fand diese Lösung die glückliche Verbindung der anderen verwendeten Techniken. Funktioniert einwandfrei und hat keinen Einfluss auf die Lokalisierung.
Trevorc
17
Tolle Lösung !! Viel nützlicher als die am besten bewerteten Antworten
Sasha
11
Ein Problem bei diesem Ansatz besteht darin, dass Sie versuchen, return View(viewmodel)in dem Fall, in dem Ihr Modell Fehler aufweist, eine aufgerufene Ansicht zurückzugeben, Sendje nachdem, wie Ihr Argumentname lautet.
Schuh
15
@ Schuh - habe gerade eine ähnliche Sache gefunden. Stellen Sie sicher, dass Sie den Namen der zurückzugebenden Ansicht explizit angeben, wenn Sie diese Methode verwenden:return View("Index", viewModel)
Ajbeaven
4
Nur eine Information, wir müssen system.Reflection für MethodInfo
Vignesh Subramanian
469

Geben Sie Ihren Senden-Schaltflächen einen Namen und überprüfen Sie den gesendeten 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(); %>

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

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

Ä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 Ihr Controller sollte folgendermaßen 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());
}
Dylan Beattie
quelle
28
Schade, dass Sie auf den auf der Schaltfläche angezeigten Text angewiesen sind. Mit einer mehrsprachigen Benutzeroberfläche ist es etwas schwierig
Omu
3
Switch / case funktioniert nur mit Konstanten, daher kann die lokalisierte Version switch / case nicht verwenden. Sie müssen zu if else oder einer anderen Versandmethode wechseln.
mlibby
10
Sie sollten einen <button type = "submit" anstelle von <input type verwenden, da der Wert eines <button type nicht der Text ist;). Dann können Sie so etwas haben: <button name = "mySubmitButton" type = "submit" value = "keyValue"> YourButtonText </ button>
J4N
4
Wie würde dies funktionieren, wenn das Modell an die Aktion übergeben wird und nicht nur der Übermittlungswert?
Bizzehdee
2
Achten Sie darauf, Ihre Schaltflächen nicht als "Aktion" zu bezeichnen, wenn Sie jQuery verwenden. Es verursacht einen Konflikt innerhalb der Bibliothek, der die Aktions-URL beschädigt.
HotN
121

Sie können den Namen in der Aktion wie erwähnt überprüfen, aber Sie können überlegen, ob dies ein gutes Design ist oder nicht. Es ist eine gute Idee, die Verantwortung für die Aktion zu berücksichtigen und dieses Design nicht zu sehr mit UI-Aspekten wie Schaltflächennamen zu koppeln. Verwenden Sie also zwei Formulare und zwei 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(); %>

Außerdem verarbeiten Sie im Fall von "Abbrechen" das Formular normalerweise nicht und gehen zu einer neuen URL. In diesem Fall müssen Sie das Formular überhaupt nicht einreichen und benötigen lediglich einen Link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>
Trevor de Koekkoek
quelle
53
Dies ist in Ordnung, wenn Sie nicht für jede Senden-Schaltfläche dieselben Formulardaten benötigen. Wenn Sie alle Daten in gemeinsamer Form benötigen, ist Dylan Beattie der richtige Weg. Gibt es eine elegantere Möglichkeit, dies zu tun?
Zidane
3
Wie befindet sich in diesem Fall die Schaltfläche "Senden" neben der Schaltfläche "Abbrechen" für die visuelle Darstellung?
Kris-I
1
Dylan: Nun, für eine Schaltfläche zum Abbrechen müssen Sie die Daten überhaupt nicht senden, und es ist eine schlechte Praxis, den Controller mit den UI-Elementen zu koppeln. Wenn Sie jedoch einen mehr oder weniger generischen "Befehl" erstellen können, denke ich, dass dies in Ordnung ist, aber ich würde ihn nicht an "submitButton" binden, da dies der Name eines UI-Elements ist.
Trevor de Koekkoek
1
@Kris: Sie können Ihre Schaltflächen mit CSS positionieren und sie können sich weiterhin in 2 verschiedenen Formularabschnitten befinden.
Trevor de Koekkoek
8
Ernsthaft? riecht das nur für mich?!
99

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

Wenn Sie mehr als eine Schaltfläche haben, können Sie zwischen diesen 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 an einen dieser Parameter gesendet wird, bedeutet dies, dass auf die Schaltfläche geklickt wurde. Der Webbrowser gibt nur einen Wert für die eine Schaltfläche aus, auf die geklickt wurde. Alle anderen Werte sind null.

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

Ich mag diese Methode, 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

PabloBlamirez
quelle
2
Wenn jemand auf diese alte Frage stößt, ist dies die sauberste Antwort, wenn Sie keine HTML5-<button> -Elemente verwenden möchten. Wenn Ihnen HTML5 nichts ausmacht, verwenden Sie <Button> mit dem Wertattribut.
Kugel
Wie würden Sie es tun, wenn Sie in diesem Formular einen Ajax-Aufruf erstellen würden? Es scheint, dass form.serialize () den Namen der
Submit-
@ Kugel ist richtig, das ist immer noch die sauberste Antwort. Vielen Dank
Arif YILMAZ
45

Habe gerade einen Beitrag dazu geschrieben: Mehrere Senden-Schaltflächen mit ASP.NET MVC :

Anstatt zu verwenden ActionMethodSelectorAttribute, verwende ich im Grunde genommen, ActionNameSelectorAttributewodurch ich so tun kann, als wäre der Aktionsname so, wie ich ihn haben möchte. Glücklicherweise ActionNameSelectorAttributemuss ich nicht nur den Aktionsnamen angeben, sondern auch auswählen, ob die aktuelle Aktion mit der Anforderung übereinstimmt.

Da ist also meine Klasse (übrigens mag ich den Namen nicht besonders):

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

Um zu verwenden, definieren Sie einfach ein Formular wie folgt:

<% 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 ausprobiert) sollten diese Aktionen auch wie normale Aktionen funktionieren, sodass Sie direkt auf eine dieser Aktionen posten können.

Andrey Shchekin
quelle
1
Wunderschönen! Ich denke, das ist die eleganteste Lösung. Der Wert des submitTags wird nicht berücksichtigt, was ideal ist, da es sich um ein reines UI-Attribut handelt, das keinen Einfluss auf den Kontrollfluss haben sollte. Stattdessen wird das eindeutige nameAttribut jedes submitTags direkt in eine diskrete Aktionsmethode auf Ihrem Controller übersetzt.
Kirk Woll
+1 Für mich ist es bei weitem die beste Lösung für dieses Problem. Seit ich es implementiert habe, stelle ich fest, dass viel Verkehr durch das HttpParamActionAttribut geleitet wird, aber im Vergleich zu allen anderen Dingen, die Asp.Net MVC während der Verarbeitung einer Anfrage ausführen muss, ist dies absolut akzeptabel. Um nur zu hacken, muss ich eine leere 'Aktion' in meinen Controller einfügen, um zu verhindern, dass Resharper mich warnt, dass die Aktion 'Aktion' nicht existiert. Vielen Dank!
Samuel
Ich habe alle Lösungen überprüft und bin mir auch einig, dass dies eine schöne, elegante und einfache Lösung ist. Großartig, da es keine bedingten Anweisungen gibt und robust ist, wo Sie eine neue Controller-Aktion definieren können, wenn Sie eine neue Schaltfläche haben. Nannte meine Klasse MultiButtonActionHandler FYI ;-)
ejhost
36

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

Ali Golgol
quelle
Genial. genau das, was ich früher in Webformularen gemacht habe. Prost Kumpel
djack109
Viel einfacher als die Top-Antwort! Vielen Dank!
pabben
35

Ich würde Interessenten vorschlagen, sich die Lösung von Maarten Balliauw anzusehen . Ich finde es sehr elegant.

Falls der Link verschwindet, wird der verwendet MultiButton Attribut, das auf eine Controller-Aktion angewendet wird, um anzugeben, auf welchen Schaltflächenklick sich diese Aktion beziehen soll.

Izmoto
quelle
Dies ist die Lösung, die wir jetzt verwenden und die sehr ordentlich ist. Ist es nur MVC 2?
Simon Keep
Dies ist schön! Ich hatte das noch nie gesehen! Obwohl ich damit einverstanden bin, dass Sie möglicherweise jede Lösung neu gestalten möchten, bei der mehrere Submits verwendet werden, um nur eine Schaltfläche zu verwenden, bin ich an einer Stelle, an der ich unter Druck stehe und dies tun muss. Diese Antwort hätte gewinnen sollen!
Rikon
Dies ist eine großartige Lösung. Sehr sauber
Arnej65
Versuchte diesen Ansatz und konnte ihn in MVC3 nicht zum Laufen bringen. Eine Variation des # 1-Wählers hat für mich funktioniert.
Scott Lawrence
Kurz und bündig .. aber nicht für MVC 3+
Piotr Kula
21

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

Marc Gravell
quelle
Mit Abstand die sauberste und einfachste Lösung, die ich je gesehen habe.
Jason Evans
13

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 auf der Seite prüfen, ob der Name == "Senden" oder der Name == "Abbrechen" ...

Ironicnet
quelle
1
Das funktioniert zwar, aber ich denke, es ist falsch, zwei Elemente mit demselben Namen zu haben.
Péter
1
Es ist nicht unbedingt falsch. Dies hängt davon ab, wie Sie die Eingänge verwenden. Sie können mehrere Elemente mit demselben Namen haben und erwarten, dass mehrere Daten empfangen werden (so funktionieren die Radiobuttons und Kontrollkästchen). Aber ja, wenn Sie diese Methode verwenden, liegt es daran, dass Sie es "falsch" machen ... Deshalb habe ich "Sie könnten", aber nicht "Sie sollten" gesetzt: P
Ironicnet
12

Was ich an ActionSelectName nicht mag, ist, 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, je nachdem, was sie tut, aber ich mag nicht die Tatsache, 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 ButtonType-Parameter 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" />
Sanjuro
quelle
11

Folgendes funktioniert für mich am besten:

<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();
}
Sergey
quelle
Ich erhalte den Nullwert für onDelete und onSave in der Controller-Methode. Wissen Sie, warum?
Diganta Kumar
Beides wird nicht null sein, wenn Sie auf die entsprechende Schaltfläche klicken. Auf welche Schaltfläche klicken Sie, um die Null zu erhalten?
Sergey
11

Ich bin auch auf dieses 'Problem' gestoßen, habe aber durch Hinzufügen des nameAttributs eine ziemlich logische Lösung gefunden . 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 Schaltfläche zum Senden enthält, ist nur die aktivierte Schaltfläche zum Senden erfolgreich.
  • ...

Dies bedeutet, dass die folgenden Codeattribute valuegeändert, lokalisiert und internationalisiert werden können, ohne dass zusätzlicher Code für stark typisierte Ressourcendateien oder Konstanten erforderlich ist.

<% 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 prüfen, ob einer Ihrer bekannten Übermittlungstypen dies nicht ist 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

    }

}
Tom Hofman
quelle
Dies ist die Lösung, die wir für eine einfache Webanwendung gewählt haben, für die wir die ASP.NET WebForms-Funktionalität, jedoch innerhalb von MVC, benötigen.
BrandonG
10

Wenn Sie keine Einschränkungen für die Verwendung von HTML 5 haben, können Sie das <button>Tag mit formactionAttribut 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

Acaz Souza
quelle
9

Wenn Ihr Browser die Attributformatierung für Eingabeschaltflächen unterstützt (IE 10+, bei anderen Browsern 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") />

}
user3361233
quelle
Schauen Sie sich meine Antwort unten an, sie basiert nicht auf Entwürfen von Spezifikationen. Ihre Antwort erlaubt die Möglichkeit, verschiedene Aktions-URLs zu haben, was meine nicht tut.
Tom Hofman
9

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

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

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

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

HTML-Weg: -

Auf HTML-Weise müssen wir zwei Formulare erstellen und die Schaltfläche "Senden" in jedem der Formulare platzieren. Und die Aktion jedes Formulars zeigt auf unterschiedliche / entsprechende Aktionen. Sie können den folgenden Code sehen, den das erste Formular an "Aktion1" sendet, und das zweite Formular wird an "Aktion2" gesendet, 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 Weg: -

Wenn Sie ein Ajax-Liebhaber sind, würde Sie diese zweite Option mehr begeistern. Auf Ajax-Weise können wir zwei verschiedene Funktionen "Fun1" und "Fun1" erstellen, siehe den folgenden Code. Diese Funktionen führen Ajax-Aufrufe mithilfe von JQUERY oder einem anderen Framework durch. Jede dieser Funktionen ist mit den "OnClick" -Ereignissen der Schaltfläche "Senden" verknüpft. Jede dieser Funktionen ruft die jeweiligen 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 geben, um sie auf dem Server zu identifizieren.

Sie können sehen, dass wir den Schaltflächennamen "Speichern" und "Löschen" hinzugefügt haben. Außerdem können Sie in der Aktion feststellen, dass wir gerade den Controller-Namen "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, welche Übermittlung ausgelöst wird, wird die entsprechende Aktion aufgerufen.

Geben Sie hier die Bildbeschreibung ein

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 Sammlung "ValueProvider" enthält alle Daten, die aus dem Formular gebucht wurden. Daher wird zuerst der Wert "Name" nachgeschlagen, und wenn er in der HTTP-Anforderung gefunden wird, wird "true" oder "false" zurückgegeben.

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 der Submit diese Aktion ausführt und der Name mit dem Namen der HTML-Submit-Schaltfläche übereinstimmt, führt er die Aktion weiter aus oder 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");
        }
}
Shivprasad Koirala
quelle
7

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

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

Saajid Ismail
quelle
7

Dies ist die Technik, die ich verwenden würde und die ich hier noch nicht sehe. 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(); %>

In der Steuerung:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
mlibby
quelle
Sieht aus wie die von Ironicnet bereitgestellte Lösung.
Kris van der Mast
Sicherlich ähnlich, aber dies zeigt sowohl die Lokalisierung als auch den Controller-Code, was ich in diesem Thread nicht so gesehen habe. Ich habe diesen Thread gefunden, als ich nach einer Möglichkeit gesucht habe, und wollte dokumentieren, was ich mir für alle anderen ausgedacht habe, die möglicherweise im selben Boot sitzen.
mlibby
1
Tatsächlich ist es nicht dasselbe wie das von Ironicnet darüber hinaus. Er benutzt <input>Elemente. Ich benutze <button>, was erforderlich ist, um die Lokalisierung ohne variable Wertattribute durchzuführen.
mlibby
7

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 Attribut data-form-action 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 verwenden on().

Jay Douglass
quelle
6

Hier ist eine Erweiterungsmethode, die ich geschrieben habe, um mehrere Bild- und / oder Textschaltflächen zu verarbeiten.

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 eine Text-Senden-Schaltfläche:

<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, mit der Sie vom Controller aufrufen form.GetSubmitButtonName(). Bei Bildschaltflächen wird nach einem Formularparameter mit gesucht .x(der angibt, dass auf eine Bildschaltfläche geklickt wurde) und der Name extrahiert. Bei normalen inputSchaltflächen wird nach einem Namen gesucht, der mit beginnt, Submit_und der Befehl wird anschließend extrahiert. Da ich die Logik zur 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: Für Textschaltflächen müssen Sie dem Namen ein Präfix voranstellen Submit_. Ich bevorzuge diesen Weg, weil es bedeutet, dass Sie den Textwert (Anzeigewert) ändern können, ohne den Code ändern zu müssen. Im Gegensatz zu SELECTElementen hat eine INPUTSchaltfläche nur einen 'Wert' und kein separates 'Text'-Attribut. Meine Schaltflächen sagen verschiedene Dinge in unterschiedlichen Kontexten aus - sind aber demselben 'Befehl' zugeordnet. Ich extrahiere den Namen lieber auf diese Weise als codieren zu müssen == "Add to cart".

Simon_Weaver
quelle
Ich mag es, den Namen als Alternative zu überprüfen, weil Sie nicht immer nach dem Wert für z. Sie haben eine Liste von Elementen und jedes hat eine Schaltfläche "Löschen".
Max
6

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

Beim Versuch, die "MultipleButtonAttribute" -Lösung zu implementieren, ValueProvider.GetValue(keyValue)würde dies fälschlicherweise wieder auftretennull .

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 richtig aktualisiert wurde und ich hatte keine anderen offensichtlichen Probleme.

Also, wenn Ihr ActionNameSelectorAttributenicht funktioniert ... überprüfen Sie das.

HeatherD
quelle
6

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

Markup . Der Schaltflächenname muss mit verschlüsselt sein"action:[controllerMethodName]"

( Beachten Sie die Verwendung des C # 6- Namens der API, die einen typspezifischen Verweis 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 CallerMemberNameGüte.

[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;
    }
}
Aaron Hudon
quelle
Obwohl dies ein guter Ansatz ist, können Sie den integrierten MVC-Modellordner nicht verwenden, da er das Attribut "Name" der Schaltflächen verwendet.
ooXei1sh
Der Zweck dieser Lösung ist eine Umgehung des MVC-Post-Routings. Bitte beschreiben Sie eine Verbesserung.
Aaron Hudon
6
[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>

    }
Mahendra
quelle
Dies ist ein weiterer nützlicher Link , der verschiedene Arten der Formularpost erklärt.
Himalaya Garg
5

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

Ich habe es in CodeProject beschrieben. Mehrere 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 vorhanden sind.

Codetuner
quelle
5
//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();
        }
SHAURAJ SINGH
quelle
Sie haben es vielleicht nicht bemerkt, aber dieselbe Antwort wurde bereits einige Male auf diese Frage gepostet.
Andrew Barber
2
Außerdem scheinen Sie Antworten zu veröffentlichen, die nur Code enthalten, ohne Erklärung. Würden Sie eine Erzählung hinzufügen, um zu erklären, warum der Code funktioniert und was ihn zu einer Antwort auf die Frage macht? Dies wäre sehr hilfreich für die Person, die die Frage stellt, und für alle anderen, die mitkommen.
Andrew Barber
2
Klar, es funktioniert gut. Aber diese Antwort wurde schon vor langer Zeit von anderen gegeben . Und sie enthielten Erklärungen, warum es auch funktioniert.
Andrew Barber
5

Dies 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 ohne Multi-Submit-Button.

Vielen Dank


quelle
Link derzeit defekt, dies ist die nächste archivierte Version, die ich finden konnte: web.archive.org/web/20110706230408/http://blogs.sonatribe.com/…
Ian Kemp
Hallo Ian - danke, dass du das ausgegraben hast - ich habe es hier neu gepostet
4

Geänderte Version der HttpParamActionAttributeMethode, jedoch mit einer Fehlerbehebung, die bei abgelaufenen / ungültigen Sitzungspostbacks keinen Fehler verursacht. Um festzustellen, ob dies ein Problem mit Ihrer aktuellen Site ist, öffnen Sie das Formular in einem Fenster und kurz bevor Sie auf Saveoder klicken Publish, öffnen Sie ein doppeltes Fenster und melden Sie sich ab. Kehren Sie nun zu Ihrem ersten Fenster zurück und versuchen Sie, Ihr Formular mit einer der beiden Schaltflächen zu senden. Für mich ist ein Fehler aufgetreten, daher löst diese Änderung das Problem für mich. Der Kürze halber lasse ich ein paar Sachen weg, aber Sie sollten auf die Idee kommen. Die wichtigsten Teile sind die Einbeziehung vonActionName in das Attribut und die Sicherstellung, 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;
    }
}

Regler

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

Aussicht

@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" />
}
Nick Albrecht
quelle
3

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

Sie können es so verwenden:

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

Und es macht so:

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

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

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

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

});
Missgeschick
quelle
3

Basierend auf der Antwort von mkozicki habe ich eine etwas andere Lösung gefunden. Ich benutze immer noch ActionNameSelectorAttributeAber ich musste zwei Schaltflächen 'Speichern' und 'Synchronisieren' handhaben. Sie machen fast das gleiche, also wollte ich nicht 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;
    }
}

Aussicht

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

Regler

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

Ich möchte auch darauf hinweisen, dass ich, wenn Aktionen andere Dinge tun, wahrscheinlich dem Beitrag von mkozicki folgen würde.

Petr J.
quelle
1

Ich habe eine ActionButton- Methode für den HtmlHelper erstellt . Es wird mit einem wenig normalen Eingabeknopf erzeugt Javascript in dem Ereignisse OnClick , das das Formular mit der angegebenen Controller / Aktion vorlegen wird.

Sie benutzen 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 Code der Erweiterungsmethode:

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 nur aus der VB-DLL dekompiliert, damit er etwas verschönert werden kann ... 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 haben verschiedene Parameter, aber zur Vereinfachung der Verwendung können Sie eine Überlastung erzeugen, die nur die Parameter verwendet, die Sie benötigen.

Max
quelle