Jak obsługiwać wiele przycisków przesyłania w programie ASP.NET MVC Framework?

733

Czy istnieje jakiś prosty sposób obsługi wielu przycisków przesyłania z tego samego formularza? Na przykład:

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

Masz pomysł, jak to zrobić w programie ASP.NET Framework Beta? Wszystkie przykłady, w których szukałem Google, mają w sobie pojedyncze przyciski.

Łup
źródło
6
Warto wspomnieć, że zaczynając od ASP.NET Core, istnieją znacznie łatwiejsze rozwiązania niż te wymienione tutaj.
Steven Jeuris
Ten samouczek może pomóc: przesłanie formularza do różnych metod działania w ASP.NET MVC
Hooman Bahreini 10.09.19

Odpowiedzi:

629

Oto najbardziej przejrzyste, oparte na atrybutach rozwiązanie problemu wielokrotnego przycisku przesyłania, oparte w dużej mierze na poście i komentarzach Maarten Balliauw .

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

brzytwa:

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

i kontroler:

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

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

Aktualizacja: strony Razor wyglądają tak, jakby zapewniały tę samą funkcjonalność po wyjęciu z pudełka. W przypadku nowego rozwoju może być preferowane.

mkozicki
źródło
3
Odkryłem, że to rozwiązanie jest szczęśliwym połączeniem innych używanych technik. Działa idealnie i nie wpływa na lokalizację.
trevorc
17
Świetne rozwiązanie !! Dużo bardziej przydatne niż te najlepiej ocenione odpowiedzi
Sasha
11
Problem z tym podejściem polega na tym, że jeśli spróbujesz return View(viewmodel)w przypadku, gdy twój model zawiera błędy, spróbuje zwrócić widok o nazwie Sendlub w zależności od nazwy twojego argumentu.
But
15
@Buty - właśnie znalazłem podobną rzecz. Upewnij się, że jawnie określasz nazwę widoku do zwrócenia, jeśli używasz tej metody:return View("Index", viewModel)
ajbeaven
4
tylko informację, musimy dodać system. Refleksja dla MethodInfo
Vignesh Subramanian
469

Nadaj przyciskom przesyłania nazwę, a następnie sprawdź przesłaną wartość w metodzie kontrolera:

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

wysyłanie do

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

}

EDYTOWAĆ:

Aby rozszerzyć to podejście do pracy ze zlokalizowanymi witrynami, odizoluj swoje wiadomości gdzie indziej (np. Kompilując plik zasobów do silnie typowanej klasy zasobów)

Następnie zmodyfikuj kod, aby działał jak:

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

a twój kontroler powinien wyglądać tak:

// 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
źródło
28
szkoda, że ​​polegasz na tekście wyświetlanym na przycisku, jest to dość trudne z wielojęzycznym interfejsem użytkownika
Omu
3
Switch / case działa tylko ze stałymi, więc zlokalizowana wersja nie może używać przełącznika / case. Musisz przełączyć się na if else lub inną metodę wysyłki.
mlibby,
10
powinieneś użyć <button type = "upload" zamiast <typ wejściowy, ponieważ wartość typu <button nie jest tekstem;). Następnie możesz mieć coś takiego: <button name = "mySubmitButton" type = "upload" value = "keyValue"> YourButtonText </button>
J4N
4
Jak to działa z przekazywaniem modelu do akcji zamiast samej wartości przesyłania?
bizzehdee
2
Uważaj, aby nie nazwać przycisków „akcja”, jeśli używasz jQuery. Powoduje konflikt w bibliotece, który psuje adres URL akcji.
HotN
121

Możesz sprawdzić nazwę w akcji, jak już wspomniano, ale możesz rozważyć, czy jest to dobry projekt. Dobrym pomysłem jest wzięcie pod uwagę odpowiedzialności za działanie i niepowiązanie tego projektu zbytnio z aspektami interfejsu użytkownika, takimi jak nazwy przycisków. Rozważ więc użycie 2 formularzy i 2 akcji:

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

Ponadto w przypadku „Anuluj” zazwyczaj nie przetwarzasz formularza i przechodzisz do nowego adresu URL. W takim przypadku nie musisz wcale przesyłać formularza, wystarczy link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>
Trevor de Koekkoek
źródło
53
Jest to w porządku, gdy nie potrzebujesz tych samych danych formularza dla każdego przycisku przesyłania. Jeśli potrzebujesz wszystkich danych w wspólnej formie, to Dylan Beattie jest dobrym rozwiązaniem. Czy jest na to bardziej elegancki sposób?
zidane
3
Co do prezentacji wizualnej, w jaki sposób w tym przypadku przycisk „Wyślij” obok przycisku „Anuluj”?
Kris-I
1
Dylan: Cóż, jeśli chodzi o przycisk anulowania, wcale nie musisz przesyłać danych, a łączenie kontrolera z elementami interfejsu jest złą praktyką. Jeśli jednak możesz wykonać bardziej lub mniej ogólne „polecenie”, to myślę, że jest w porządku, ale nie powiązałbym go z „submButton”, ponieważ taka jest nazwa elementu interfejsu użytkownika.
Trevor de Koekkoek
1
@Kris: możesz pozycjonować przyciski za pomocą CSS, a one nadal mogą znajdować się w 2 różnych sekcjach formularza.
Trevor de Koekkoek
8
poważnie? czy to nie pachnie nikomu oprócz mnie ?!
98

Eilon sugeruje, że możesz to zrobić w następujący sposób:

Jeśli masz więcej niż jeden przycisk, możesz je rozróżnić, nadając każdemu przyciskowi nazwę:

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

W metodzie akcji kontrolera możesz dodawać parametry nazwane po nazwach tagów wejściowych HTML:

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

Jeśli jakaś wartość zostanie wysłana do jednego z tych parametrów, oznacza to, że kliknięto przycisk. Przeglądarka internetowa opublikuje wartość tylko dla jednego klikniętego przycisku. Wszystkie pozostałe wartości będą zerowe.

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

Podoba mi się ta metoda, ponieważ nie opiera się ona na właściwości value przycisków przesyłania, która jest bardziej prawdopodobna do zmiany niż przypisane nazwy i nie wymaga włączenia javascript

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

PabloBlamirez
źródło
2
Jeśli ktoś napotka stare pytanie, jest to najczystsza odpowiedź, jeśli nie chcesz używać elementów <button> HTML5. Jeśli nie przeszkadza Ci HTML5, użyj <button> z atrybutem wartości.
Kugel,
Jak byś to zrobił, tworząc wywołanie ajax w tym formularzu. Wygląda na to, że form.serialize () nie odbiera nazwy przycisku przesłania ..
mko
@ Kugel ma rację, to wciąż najczystsza odpowiedź. Dzięki
Arif YILMAZ,
45

Właśnie napisałem o tym: Wiele przycisków przesyłania za pomocą ASP.NET MVC :

Zasadniczo, zamiast używać ActionMethodSelectorAttribute, używam ActionNameSelectorAttribute, co pozwala mi udawać, że nazwa akcji jest taka, jaką chcę. Na szczęście ActionNameSelectorAttributenie tylko każe mi określać nazwę akcji, ale mogę wybrać, czy bieżąca akcja pasuje do żądania.

Oto moja klasa (przy okazji nie przepadam za tym imieniem):

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

Aby użyć, wystarczy zdefiniować taki formularz:

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

i kontroler z dwiema metodami

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

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

Jak widać, ten atrybut wcale nie wymaga od ciebie niczego określenia. Ponadto nazwy przycisków są tłumaczone bezpośrednio na nazwy metod. Dodatkowo (nie próbowałem tego) powinny one również działać jako normalne akcje, więc możesz pisać bezpośrednio na dowolnym z nich.

Andrey Shchekin
źródło
1
Piękny! Myślę, że to najbardziej eleganckie rozwiązanie. Eliminuje wartość tego submittagu z uwzględnieniem, który jest idealny, ponieważ jest to atrybut pure-UI, które powinny mieć żadnego wpływu na kontroli przepływu. Zamiast tego unikalny nameatrybut każdego submitznacznika przekłada się bezpośrednio na dyskretną metodę działania na kontrolerze.
Kirk Woll,
+1 Dla mnie to zdecydowanie najlepsze rozwiązanie tego problemu. Odkąd go zaimplementowałem, zauważam, że wiele ruchu przechodzi przez HttpParamActionAttribut, ale w porównaniu do wszystkich innych rzeczy, które Asp.Net MVC musi zrobić podczas przetwarzania żądania, jest to całkowicie akceptowalne. Aby tylko zhakować, co muszę zrobić, umieść pustą „Akcję” o nazwie w moim kontrolerze, aby Resharper nie ostrzegł mnie, że akcja „Akcja” nie istnieje. Dziękuję Ci bardzo!
Samuel
Przejrzałem wszystkie rozwiązania i również zgadzam się, że jest to ładne eleganckie, proste rozwiązanie. Świetnie, bo nie ma żadnych instrukcji warunkowych i solidny, w których można zdefiniować nową akcję kontrolera, gdy masz nowy przycisk. Zadzwoniłem do mojej klasy MultiButtonActionHandler FYI ;-)
ejhost
36

jest krótki i zawiera:

Odpowiedzi udzielił Jeroen Dop

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

i zrób tak w kodzie

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

Powodzenia.

Ali Golgol
źródło
Niesamowite. dokładnie to, co robiłem w formularzach internetowych. Na zdrowie kolego
djack109 10.07.17
O wiele prostsze niż najlepsza odpowiedź! Dzięki!
pabben
35

Proponuję zainteresowanym stronom zapoznać się z rozwiązaniem Maarten Balliauw . Myślę, że jest bardzo elegancki.

W przypadku, gdy link zniknie, używa MultiButtonatrybutu zastosowanego do akcji kontrolera, aby wskazać, do którego przycisku należy się odnieść.

Izmoto
źródło
Tego rozwiązania używamy teraz i jest bardzo schludne. Czy to jednak tylko MVC 2?
Simon Keep
To jest piękne! Nie widziałem tego wcześniej! Chociaż zgadzam się, że możesz chcieć przeprojektować dowolne rozwiązanie, które używa wielu zgłoszeń, aby używało tylko jednego przycisku, jestem w miejscu, w którym jestem zahamowany i muszę to zrobić. Ta odpowiedź powinna była wygrać!
Rikon
To świetne rozwiązanie. Bardzo czyste
Arnej65
Wypróbowałem to podejście i nie udało się go uruchomić w MVC3. Odmiana pierwszego zdobywcy głosów działała dla mnie.
Scott Lawrence
Krótki i słodki .. ale nie dla mvc 3+
Piotr Kula
21

Powinieneś być w stanie nazwać przyciski i nadać im wartość; następnie zamapuj tę nazwę jako argument akcji. Alternatywnie użyj 2 oddzielnych łączy akcji lub 2 formularzy.

Marc Gravell
źródło
Zdecydowanie najczystsze i najłatwiejsze rozwiązanie, jakie widziałem.
Jason Evans
13

Możesz napisać:

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

A następnie na stronie sprawdź, czy nazwa == „Wyślij” lub nazwa == „Anuluj” ...

Ironicnet
źródło
1
Chociaż to działa, ale myślę, że niewłaściwą praktyką jest posiadanie dwóch elementów o tej samej nazwie.
Péter
1
To nie jest konieczne źle. To zależy od tego, jak korzystasz z danych wejściowych. Możesz mieć wiele elementów o tej samej nazwie i oczekujących otrzymania wielu danych (w ten sposób działają przyciski radiowe i pola wyboru). Ale tak, jeśli używasz tej metody, to dlatego, że robisz to „źle” ... Dlatego
dodałem
12

W ActionSelectName nie podoba mi się to, że IsValidName jest wywoływana dla każdej metody akcji w kontrolerze; Nie wiem, dlaczego to działa w ten sposób. Lubię rozwiązanie, w którym każdy przycisk ma inną nazwę w zależności od tego, co robi, ale nie podoba mi się fakt, że musisz mieć tyle parametrów w metodzie akcji, co przyciski w formularzu. Utworzyłem wyliczenie dla wszystkich typów przycisków:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Zamiast ActionSelectName używam 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;
            }
        }
    }
}

Filtr znajdzie nazwę przycisku w danych formularza i jeśli nazwa przycisku odpowiada dowolnemu typowi przycisku zdefiniowanemu w wyliczeniu, znajdzie parametr ButtonType wśród parametrów akcji:

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

a następnie w widokach mogę użyć:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />
sanjuro
źródło
11

Oto, co działa najlepiej dla mnie:

<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();
}
Siergiej
źródło
Otrzymuję wartość null dla onDelete i onSave w metodzie kontrolera. Wiesz dlaczego?
Diganta Kumar
Żadna z nich nie będzie zerowa, jeśli klikniesz odpowiedni przycisk. Który przycisk klikniesz, aby uzyskać wartość zerową?
Siergiej
11

Natknąłem się również na ten „problem”, ale znalazłem dość logiczne rozwiązanie, dodając nameatrybut. Nie mogłem sobie przypomnieć tego problemu w innych językach.

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

  • ...
  • Jeśli formularz zawiera więcej niż jeden przycisk wysyłania, tylko aktywowany przycisk wysyłania powiedzie się.
  • ...

Oznacza to, że następujące valueatrybuty kodu można zmieniać, lokalizować, internacjonalizować bez potrzeby dodatkowego sprawdzania kodu silnie typowanych plików zasobów lub stałych.

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

Po stronie odbierającej wystarczy sprawdzić, czy któryś ze znanych typów przesyłania nie jest 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
źródło
Jest to rozwiązanie, które wybraliśmy dla prostej aplikacji internetowej, w której chcieliśmy funkcjonalności ASP.NET WebForms, ale w MVC.
BrandonG
10

Jeśli nie masz ograniczeń dotyczących używania HTML 5, możesz użyć <button>znacznika z formactionatrybutem:

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

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

Acaz Souza
źródło
9

Jeśli Twoja przeglądarka obsługuje formułowanie atrybutów dla przycisków wprowadzania (IE 10+, nie jestem pewien co do innych przeglądarek), powinny działać następujące czynności:

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

}
użytkownik3361233
źródło
Spójrz na moją odpowiedź poniżej, nie opiera się ona na projektach specyfikacji. Twoja odpowiedź pozwala na posiadanie różnych adresów URL akcji, czego moje nie.
Tom Hofman
9

Istnieją trzy sposoby rozwiązania powyższego problemu

  1. Sposób HTML
  2. Jquery way
  3. Sposób „ActionNameSelectorAttribute”

Poniżej znajduje się wideo, które podsumowuje wszystkie trzy podejścia w sposób demonstracyjny.

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

Sposób HTML: -

W sposób HTML musimy utworzyć dwa formularze i umieścić przycisk „Prześlij” w każdym formularzu. I działanie każdej formy będzie wskazywać na różne / odpowiednie działania. Możesz zobaczyć poniższy kod, który pierwszy formularz publikuje w „Akcji 1”, a drugi formularz w „Akcji 2”, w zależności od kliknięcia przycisku „Prześlij”.

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

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

Sposób Ajax: -

Jeśli jesteś miłośnikiem Ajax, ta druga opcja bardziej Cię podnieci. W sposób Ajax możemy stworzyć dwie różne funkcje „Fun1” i „Fun1”, patrz poniższy kod. Te funkcje będą wykonywać wywołania Ajax przy użyciu JQUERY lub dowolnego innego frameworka. Każda z tych funkcji jest powiązana ze zdarzeniami „OnClick” przycisku „Prześlij”. Każda z tych funkcji wywołuje odpowiednie nazwy akcji.

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

Korzystanie z „ActionNameSelectorAttribute”: -

To świetna i czysta opcja. „ActionNameSelectorAttribute” to prosta klasa atrybutów, w której możemy napisać logikę decyzyjną, która zadecyduje, która akcja może zostać wykonana.

Pierwszą rzeczą jest to, że w HTML musimy nadać odpowiednie nazwy przyciskom przesyłania w celu ich identyfikacji na serwerze.

Widać, że umieściliśmy „Zapisz” i „Usuń” w nazwach przycisków. Możesz również zauważyć, że w akcji właśnie umieściliśmy nazwę kontrolera „Klient”, a nie konkretną nazwę akcji. Oczekujemy, że o nazwie akcji decyduje „ActionNameSelectorAttribute”.

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

Tak więc po kliknięciu przycisku wysyłania najpierw trafia on w atrybut „ActionNameSelector”, a następnie w zależności od tego, które polecenie zostało uruchomione, wywołuje odpowiednią akcję.

wprowadź opis zdjęcia tutaj

Pierwszym krokiem jest więc utworzenie klasy, która dziedziczy po klasie „ActionNameSelectorAttribute”. W tej klasie stworzyliśmy prostą właściwość „Nazwa”.

Musimy również zastąpić funkcję „IsValidName”, która zwraca true lub flase. Ta funkcja zapisuje logikę, czy akcja musi zostać wykonana, czy nie. Jeśli więc ta funkcja zwróci wartość true, akcja zostanie wykonana lub nie.

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;

        }
    }

Głównym sercem powyższej funkcji jest poniższy kod. Kolekcja „ValueProvider” zawiera wszystkie dane wysłane z formularza. Najpierw sprawdza wartość „Nazwa” i jeśli zostanie znaleziona w żądaniu HTTP, zwraca wartość true lub w przeciwnym razie zwraca wartość false.

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

Tę klasę atrybutów można następnie udekorować odpowiednią akcją i podać odpowiednią wartość „Nazwa”. Więc jeśli przesłanie trafia w tę akcję i jeśli nazwa pasuje do nazwy przycisku HTML przesłania, wówczas wykonuje akcję dalej, w przeciwnym razie nie.

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
źródło
7

David Findley pisze o 3 różnych opcjach, które możesz zrobić, na swoim blogu ASP.Net.

Przeczytaj artykuł wiele przycisków w tej samej formie, aby zobaczyć jego rozwiązania oraz zalety i wady każdego z nich. IMHO zapewnia bardzo eleganckie rozwiązanie, które wykorzystuje atrybuty, którymi ozdobisz swoje działanie.

Saajid Ismail
źródło
7

Jest to technika, której użyłbym i jeszcze jej nie widzę. Link (opublikowany przez Saajida Ismaila), który inspiruje to rozwiązanie, to http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form .aspx ). Dostosowuje odpowiedź Dylana Beattiego, aby bez problemu przeprowadzać lokalizację.

W widoku:

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

W kontrolerze:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
mlibby
źródło
Wygląda na to, że dostarczone rozwiązanie Ironicnet.
Kris van der Mast
Z pewnością podobne, ale pokazuje to zarówno lokalizację, jak i kod kontrolera, czego nie widziałem w tym wątku. Znalazłem ten wątek, szukając sposobu na zrobienie tego i chciałem udokumentować, co wymyśliłem dla każdego, kto mógłby być na tej samej łodzi.
mlibby,
1
W rzeczywistości to nie to samo, co Ironicnet. Używa <input>elementów. Używam <button>, co jest wymagane do przeprowadzenia lokalizacji bez posiadania atrybutów o zmiennej wartości.
mlibby,
7

Ten skrypt pozwala określić atrybut data-form-action, który będzie działał jako atrybut formaction HTML5 we wszystkich przeglądarkach (w dyskretny sposób):

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

Formularz zawierający przycisk zostanie wysłany na adres URL określony w atrybucie data-form-action:

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

Wymaga to jQuery 1.7. W przypadku poprzednich wersji należy użyć live()zamiast on().

Jay Douglass
źródło
6

Oto metoda rozszerzenia, którą napisałem, aby obsługiwać wiele przycisków obrazów i / lub tekstu.

Oto kod HTML przycisku graficznego:

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

lub w przypadku przycisku przesłania tekstu:

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

Oto metoda rozszerzenia, którą wywołujesz z kontrolera form.GetSubmitButtonName(). W przypadku przycisków obrazu szuka parametru formularza z .x(który wskazuje, że kliknięto przycisk obrazu) i wyodrębnia nazwę. W przypadku zwykłych inputprzycisków szuka nazwy zaczynającej się od, Submit_a następnie wydobywa polecenie. Ponieważ abstrahuję od logiki określania „polecenia”, możesz przełączać między przyciskami obraz + tekst na kliencie bez zmiany kodu po stronie serwera.

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

Uwaga: w przypadku przycisków tekstowych musisz poprzedzić nazwę nazwą Submit_. Wolę tak, ponieważ oznacza to, że możesz zmienić wartość tekstu (wyświetlania) bez konieczności zmiany kodu. W przeciwieństwie do SELECTelementów INPUTprzycisk ma tylko „wartość” i nie ma osobnego atrybutu „tekst”. Moje przyciski mówią różne rzeczy w różnych kontekstach - ale mapują na to samo „polecenie”. Wolę wyodrębnić nazwę w ten sposób niż kodować == "Add to cart".

Simon_Weaver
źródło
Lubię sprawdzać nazwę jako alternatywę, ponieważ nie zawsze możesz sprawdzić wartość np. masz listę elementów i każdy z nich ma przycisk „Usuń”.
Maks.
6

Nie mam wystarczającej liczby przedstawicieli, aby skomentować w odpowiednim miejscu, ale spędziłem nad tym cały dzień, więc chcę się tym podzielić.

Podczas próby wdrożenia rozwiązania „MultipleButtonAttribute” ValueProvider.GetValue(keyValue)niepoprawnie powróci null.

Okazało się, że odwoływałem się do System.Web.MVC w wersji 3.0, kiedy powinien to być 4.0 (inne zestawy to 4.0). Nie wiem, dlaczego mój projekt nie zaktualizował się poprawnie i nie miałem innych oczywistych problemów.

Więc jeśli ActionNameSelectorAttributenie działa ... sprawdź to.

HeatherD
źródło
6

Jestem spóźniony na imprezę, ale proszę bardzo ... Moja implementacja pożycza od @mozozickiego, ale wymaga mniej zakodowanych ciągów, aby się pomylić. Wymagany Framework 4.5+ . Zasadniczo nazwa metody kontrolera powinna być kluczem do routingu.

Markup . Nazwa przycisku musi być wpisana za pomocą"action:[controllerMethodName]"

(zawiadomienie korzystanie z C # 6 nameof API, zapewniając typu konkretne odniesienie do nazwy metody kontrolera, który chcesz wywołać.

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

Kontroler :

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

Atrybut Magia . Zwróć uwagę na CallerMemberNamedobroć.

[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
źródło
Chociaż jest to miłe podejście, nie będzie można użyć wbudowanego spoiwa modelu mvc, ponieważ wykorzystuje on atrybut „nazwa” przycisków.
ooXei1sh
Celem tego rozwiązania jest obejście routingu pocztowego MVC. Proszę opisać ulepszenie.
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
źródło
To kolejny przydatny link wyjaśniający różne sposoby wysyłania formularzy.
Himalaya Garg
5

Próbowałem dokonać syntezy wszystkich rozwiązań i stworzyłem atrybut [ButtenHandler], który ułatwia obsługę wielu przycisków w formularzu.

Opisałem to na CodeProject Wiele sparametryzowanych (zlokalizowanych) przycisków formularzy w ASP.NET MVC .

Aby obsłużyć prosty przypadek tego przycisku:

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

Będziesz miał coś w rodzaju następującej metody działania:

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

Zauważ, jak nazwa przycisku odpowiada nazwie metody akcji. W artykule opisano także, jak mieć przyciski z wartościami i przyciski z indeksami.

codetuner
źródło
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
źródło
Być może nie zdawałeś sobie z tego sprawy, ale ta sama odpowiedź została już postawiona kilka razy na to pytanie.
Andrew Barber
2
Ponadto wydaje się, że publikujesz odpowiedzi zawierające tylko kod, bez wyjaśnień. Czy zastanowiłbyś się nad dodaniem narracji wyjaśniającej, dlaczego kod działa i co czyni go odpowiedzią na pytanie? Byłoby to bardzo pomocne dla osoby zadającej pytanie i każdej innej, która się pojawi.
Andrew Barber
2
Jasne, działa dobrze. Ale ta odpowiedź już dawno dawali inni . Zawierały też wyjaśnienia, dlaczego to działa.
Andrew Barber
5

to najlepszy sposób, jaki znalazłem:

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

Oto kod:

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

Ciesz się bez zapachu wieloma przyciskami przesyłania w przyszłości.

Dziękuję Ci


źródło
Link obecnie zepsuty, jest to najbliższa zarchiwizowana wersja, jaką udało mi się znaleźć: web.archive.org/web/20110706230408/http://blogs.sonatribe.com/…
Ian Kemp
Cześć Ian - dziękuję za wykopanie tego - opublikowałem
4

Zmodyfikowana wersja HttpParamActionAttributemetody, ale z poprawką błędu, która nie powoduje błędu w wygasających / nieprawidłowych zwrotach sesji. Aby sprawdzić, czy jest to problem z bieżącą witryną, otwórz formularz w oknie i tuż przed kliknięciem Savelub Publishotwórz zduplikowane okno i wyloguj się. Teraz wróć do pierwszego okna i spróbuj wysłać formularz za pomocą dowolnego przycisku. Dla mnie wystąpił błąd, więc ta zmiana rozwiązuje dla mnie ten problem. Pomijam kilka rzeczy ze względu na zwięzłość, ale powinieneś o tym pomyśleć. Kluczowymi częściami są włączenie ActionNameatrybutu i upewnienie się, że przekazana nazwa jest nazwą Widoku, który pokazuje formularz

Klasa atrybutu

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

Kontroler

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

Widok

@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
źródło
3

Moje podejście do JQuery przy użyciu metody rozszerzenia:

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

Możesz użyć tego w następujący sposób:

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

I renderuje się tak:

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

Do każdego przycisku wysyłania wystarczy dodać:

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

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

});
nieszczęście
źródło
3

Na podstawie odpowiedzi mkozickiego wpadam na nieco inne rozwiązanie. Nadal używam ActionNameSelectorAttributeAle musiałem obsługiwać dwa przyciski „Zapisz” i „Synchronizuj”. Robią prawie to samo, więc nie chciałem mieć dwóch akcji.

atrybut :

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

widok

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

kontroler

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

Chciałbym również zauważyć, że jeśli działania będą robić różne rzeczy, prawdopodobnie podążę za postem mkozickiego.

Petr J
źródło
1

Utworzyliśmy ActionButton metodę HtmlHelper . Wygeneruje normalny przycisk wejściowy z odrobiną javascript w zdarzeniu OnClick , który prześle formularz do określonego kontrolera / akcji.

Tak używasz pomocnika

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

wygeneruje następujący kod HTML

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

Oto kod metody rozszerzenia:

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 # (kod C # jest właśnie dekompilowany z biblioteki DLL VB, więc można uzyskać upiększenie ... ale czas jest tak krótki :-))

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

Te metody mają różne parametry, ale dla łatwości użycia możesz stworzyć przeciążenie, które zabierze tylko potrzebne parametry.

Max
źródło