簡體   English   中英

你如何處理 ASP.NET MVC 框架中的多個提交按鈕?

[英]How do you handle multiple submit buttons in ASP.NET MVC Framework?

是否有一些簡單的方法可以處理來自同一表單的多個提交按鈕? 例如:

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

知道如何在 ASP.NET Framework Beta 中執行此操作嗎? 我用谷歌搜索過的所有示例中都有單個按鈕。

這是一個基於屬性的基於屬性的解決方案,主要基於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;
    }
}

剃刀:

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

和控制器:

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

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

更新: Razor 頁面看起來提供了開箱即用的相同功能。 對於新的開發,它可能更可取。

為提交按鈕命名,然后檢查控制器方法中提交的值:

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

發布到

public class MyController : Controller {
    public ActionResult MyAction(string submitButton) {
        switch(submitButton) {
            case "Send":
                // delegate sending to another controller action
                return(Send());
            case "Cancel":
                // call another action to perform the cancellation
                return(Cancel());
            default:
                // If they've submitted the form without a submitButton, 
                // just return the view again.
                return(View());
        }
    }

    private ActionResult Cancel() {
        // process the cancellation request here.
        return(View("Cancelled"));
    }

    private ActionResult Send() {
        // perform the actual send operation here.
        return(View("SendConfirmed"));
    }

}

編輯:

要擴展此方法以使用本地化站點,請將您的消息隔離在其他地方(例如,將資源文件編譯為強類型資源類)

然后修改代碼,使其工作方式如下:

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

你的控制器應該是這樣的:

// Note that the localized resources aren't constants, so 
// we can't use a switch statement.

if (submitButton == Resources.Messages.Send) { 
    // delegate sending to another controller action
    return(Send());

} else if (submitButton == Resources.Messages.Cancel) {
     // call another action to perform the cancellation
     return(Cancel());
}

您可以在前面提到的操作中檢查名稱,但您可能會考慮這是否是好的設計。 考慮操作的責任並且不要將此設計過多地與按鈕名稱等 UI 方面結合是一個好主意。 因此,請考慮使用 2 個表單和 2 個操作:

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

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

此外,在“取消”的情況下,您通常只是不處理表單,而是轉到一個新的 URL。 在這種情況下,您根本不需要提交表單,只需要一個鏈接:

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

Eilon 建議你可以這樣做:

如果您有多個按鈕,您可以通過為每個按鈕命名來區分它們:

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

在您的控制器操作方法中,您可以添加以 HTML 輸入標簽名稱命名的參數:

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

如果任何值被發布到這些參數之一,這意味着該按鈕是被點擊的那個。 Web 瀏覽器只會為被點擊的一個按鈕發布一個值。 所有其他值都將為空。

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

我喜歡這種方法,因為它不依賴於提交按鈕的 value 屬性,它比指定的名稱更有可能改變,並且不需要啟用 javascript

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

剛剛寫了一篇關於這個的帖子: Multiple submit buttons with ASP.NET MVC

基本上,我沒有使用ActionMethodSelectorAttribute ,而是使用ActionNameSelectorAttribute ,它允許我假裝動作名稱是我想要的任何名稱。 幸運的是, ActionNameSelectorAttribute不只是讓我指定動作名稱,而是可以選擇當前動作是否與請求匹配。

所以有我的班級(順便說一句,我不太喜歡這個名字):

public class HttpParamActionAttribute : ActionNameSelectorAttribute {
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
} 

要使用,只需定義一個這樣的表單:

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

和控制器有兩種方法

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

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

如您所見,該屬性根本不需要您指定任何內容。 此外,按鈕的名稱直接轉換為方法名稱。 此外(我還沒有嘗試過)這些也應該像正常操作一樣工作,因此您可以直接發布到其中任何一個。

它很短,很適合:

這是由Jeroen Dop回答的

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

並在后面的代碼中這樣做

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

祝你好運。

我建議感興趣的各方看看 Maarten Balliauw 的解決方案 我認為它非常優雅。

如果鏈接消失,它將使用應用於控制器操作的MultiButton屬性來指示該操作應與哪個按鈕單擊相關。

你應該能夠命名按鈕並給它們一個值; 然后將此名稱作為參數映射到操作。 或者,使用 2 個單獨的操作鏈接或 2 個表單。

你可以寫:

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

然后在頁面中檢查名稱==“發送”或名稱==“取消”...

我不喜歡 ActionSelectName 的一點是,控制器中的每個操作方法都會調用 IsValidName; 我不知道為什么它會這樣工作。 我喜歡這樣一種解決方案,其中每個按鈕根據其功能而具有不同的名稱,但我不喜歡這樣一個事實,即操作方法中的參數必須與表單中的按鈕一樣多。 我為所有按鈕類型創建了一個枚舉:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

我使用 ActionFilter 代替 ActionSelectName:

public class MultipleButtonsEnumAttribute : ActionFilterAttribute
{
    public Type EnumType { get; set; }

    public MultipleButtonsEnumAttribute(Type enumType)
    {
        EnumType = enumType;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach (var key in filterContext.HttpContext.Request.Form.AllKeys)
        {
            if (Enum.IsDefined(EnumType, key))
            {
                var pDesc = filterContext.ActionDescriptor.GetParameters()
                    .FirstOrDefault(x => x.ParameterType == EnumType);
                filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key);
                break;
            }
        }
    }
}

過濾器將在表單數據中找到按鈕名稱,如果按鈕名稱與枚舉中定義的任何按鈕類型匹配,它將在操作參數中找到 ButtonType 參數:

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

然后在視圖中,我可以使用:

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

如果您的瀏覽器支持輸入按鈕的屬性 formaction(IE 10+,不確定其他瀏覽器),那么以下應該可以工作:

@using (Html.BeginForm()){
    //put form inputs here

<input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" />

<input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") />

}

我也遇到過這個“問題”,但通過添加name屬性找到了一個相當合乎邏輯的解決方案。 我不記得在其他語言中遇到過這個問題。

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

  • ...
  • 如果一個表單包含多個提交按鈕,則只有激活的提交按鈕才能成功。
  • ...

這意味着可以更改、本地化、國際化以下代碼value屬性,而無需對強類型資源文件或常量進行額外的代碼檢查。

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="send" value="Send" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="draft" value="Save as draft" />
<% Html.EndForm(); %>`

在接收端,您只需要檢查是否有任何已知的提交類型不為null

public ActionResult YourAction(YourModel model) {

    if(Request["send"] != null) {

        // we got a send

    }else if(Request["cancel"]) {

        // we got a cancel, but would you really want to post data for this?

    }else if(Request["draft"]) {

        // we got a draft

    }

}

以下是最適合我的方法:

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

如果對 HTML 5 的使用沒有限制,可以使用<button>標簽和formaction屬性:

<form action="demo_form.asp" method="get">
   First name: <input type="text" name="fname" /><br />
   Last name: <input type="text" name="lname" /><br />
   <button type="submit">Submit</button><br />
   <button type="submit" formaction="demo_admin.asp">Submit as admin</button>
</form>

參考: http : //www.w3schools.com/html5/att_button_formaction.asp

您可以通過三種方式解決上述問題

  1. HTML方式
  2. jQuery方式
  3. “ActionNameSelectorAttribute”方式

下面的視頻以演示的方式總結了所有三種方法。

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

HTML方式:-

在 HTML 方式中,我們需要創建兩個表單並在每個表單中放置“提交”按鈕。 並且每個表單的動作都將指向不同/各自的動作。 您可以看到下面的代碼,第一個表單發布到“Action1”,第二個表單將發布到“Action2”,具體取決於單擊的“提交”按鈕。

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

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

阿賈克斯方式:-

如果您是 Ajax 愛好者,那么第二個選項會讓您更加興奮。 在 Ajax 方式中,我們可以創建兩個不同的函數“Fun1”和“Fun1”,見下面的代碼。 這些函數將使用 JQUERY 或任何其他框架進行 Ajax 調用。 這些函數中的每一個都與“提交”按鈕的“OnClick”事件綁定。 這些函數中的每一個都調用各自的動作名稱。

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<form action="/Action1" method=post>
<input type=submit name=sub1 onclick=”Fun2()”/>
</form>
<form action="/Action2" method=post>
<input type=submit name=sub2 onclick=”Fun1()”/>
</form>

使用“ActionNameSelectorAttribute”:-

這是一個偉大而干凈的選擇。 “ActionNameSelectorAttribute”是一個簡單的屬性類,我們可以在其中編寫決策邏輯來決定可以執行哪些操作。

所以第一件事是在 HTML 中,我們需要將正確的名稱放在提交按鈕上,以便在服務器上識別它們。

您可以看到我們在按鈕名稱中添加了“保存”和“刪除”。 您還可以注意到,我們剛剛在操作中放置了控制器名稱“客戶”,而不是特定的操作名稱。 我們期望動作名稱將由“ActionNameSelectorAttribute”決定。

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

所以當提交按鈕被點擊時,它首先點擊“ActionNameSelector”屬性,然后根據哪個提交被觸發它調用適當的動作。

在此處輸入圖片說明

所以第一步是創建一個繼承自“ActionNameSelectorAttribute”類的類。 在這個類中,我們創建了一個簡單的屬性“Name”。

我們還需要覆蓋返回 true 或 flase 的“IsValidName”函數。 這個函數是我們編寫一個動作是否必須執行的邏輯的地方。 因此,如果此函數返回 true,則執行操作,否則不執行。

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

        }
    }

上述函數的核心在下面的代碼中。 “ValueProvider”集合包含從表單發布的所有數據。 因此,它首先查找“Name”值,如果在 HTTP 請求中找到它,則返回 true,否則返回 false。

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

然后可以在相應的操作上裝飾該屬性類,並可以提供相應的“名稱”值。 因此,如果提交正在執行此操作,並且名稱與 HTML 提交按鈕名稱匹配,則它會進一步執行該操作,否則不會執行。

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

David Findley 在他的 ASP.Net 網絡博客上寫了大約 3 種不同的選擇來執行此操作。

閱讀文章多個按鈕相同的形式,看看他的解決方案,以及每個的優點和缺點。 恕我直言,他提供了一個非常優雅的解決方案,它利用了你用來裝飾你的動作的屬性。

這是我將使用的技術,我還沒有在這里看到它。 激發此解決方案的鏈接(由 Saajid Ismail 發布)是http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form .aspx )。 它改編了 Dylan Beattie 的答案,可以毫無問題地進行本地化。

在視圖中:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<button name="button" value="send"><%: Resources.Messages.Send %></button>
<button name="button" value="cancel"><%: Resources.Messages.Cancel %></button>
<% Html.EndForm(); %>

在控制器中:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
[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>

    }

此腳本允許指定一個 data-form-action 屬性,該屬性將在所有瀏覽器中用作 HTML5 formaction 屬性(以一種不顯眼的方式):

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

包含按鈕的表單將發布到 data-form-action 屬性中指定的 URL:

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

這需要 jQuery 1.7。 對於以前的版本,您應該使用live()而不是on()

我沒有足夠的代表在正確的地方發表評論,但我花了一整天的時間所以想分享。

在嘗試實施“MultipleButtonAttribute”解決方案時, ValueProvider.GetValue(keyValue)會錯誤地返回null

結果我引用了 System.Web.MVC 版本 3.0,而它應該是 4.0(其他程序集是 4.0)。 我不知道為什么我的項目沒有正確升級,我沒有其他明顯的問題。

因此,如果您的ActionNameSelectorAttribute不起作用...請檢查一下。

我參加聚會已經很晚了,但是這里是......我的實現借用了@mkozicki,但需要更少的硬編碼字符串來出錯。 需要框架 4.5+ 本質上,控制器方法名稱應該是路由的關鍵。

標記 按鈕名稱必須以"action:[controllerMethodName]"為鍵

(請注意 C#6 nameof API 的使用,提供對您希望調用的控制器方法名稱的特定於類型的引用。

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

控制器

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

屬性魔法 注意CallerMemberName的使用好處。

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

這是我編寫的用於處理多個圖像和/或文本按鈕的擴展方法。

這是圖像按鈕的 HTML:

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

或文本提交按鈕:

<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart"  />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today"  />

這是您使用form.GetSubmitButtonName()從控制器調用的擴展方法。 對於圖像按鈕,它查找帶有.x的表單參數(表示單擊了圖像按鈕)並提取名稱。 對於常規input按鈕,它查找以Submit_開頭的名稱, Submit_提取命令。 因為我抽象出了確定“命令”的邏輯,您可以在客戶端上的圖像 + 文本按鈕之間切換,而無需更改服務器端代碼。

public static class FormCollectionExtensions
{
    public static string GetSubmitButtonName(this FormCollection formCollection)
    {
        return GetSubmitButtonName(formCollection, true);
    }

    public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
    {
        var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
        var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();

        if (textButton != null)
        {
            return textButton.Substring("Submit_".Length);
        }

        // we got something like AddToCart.x
        if (imageButton != null)
        {
            return imageButton.Substring(0, imageButton.Length - 2);
        }

        if (throwOnError)
        {
            throw new ApplicationException("No button found");
        }
        else
        {
            return null;
        }
    }
}

注意:對於文本按鈕,您必須在名稱前加上Submit_ 我更喜歡這種方式,因為這意味着您可以更改文本(顯示)值而無需更改代碼。 SELECT元素不同, INPUT按鈕只有一個“值”而沒有單獨的“文本”屬性。 我的按鈕在不同的上下文中說不同的東西 - 但映射到相同的“命令”。 我更喜歡以這種方式提取名稱,而不是必須為== "Add to cart"編碼。

我試圖對所有解決方案進行綜合,並創建了一個 [ButtenHandler] 屬性,它可以輕松處理表單上的多個按鈕。

我已經在 ASP.NET MVC 中的CodeProject Multiple parameterized (localizable) 表單按鈕上描述了它。

要處理此按鈕的簡單情況:

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

您將擁有類似於以下操作方法的內容:

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

注意按鈕的名稱如何與操作方法的名稱匹配。 本文還介紹了如何使用帶值的按鈕和帶索引的按鈕。

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

這是我發現的最好方法:

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

這是代碼:

    /// <summary>
    /// ActionMethodSelector to enable submit buttons to execute specific action methods.
    /// </summary>
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
   {
        /// <summary>
        /// Gets or sets the value to use to inject the index into
        /// </summary>
       public string TargetArgument { get; set; }

       /// <summary>
       /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
       /// </summary>
       public string Action { get; set; }

       /// <summary>
       /// Gets or sets the regular expression to match the action.
       /// </summary>
       public string ActionRegex { get; set; }

       /// <summary>
       /// Determines whether the action method selection is valid for the specified controller context.
       /// </summary>
       /// <param name="controllerContext">The controller context.</param>
       /// <param name="methodInfo">Information about the action method.</param>
       /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {

           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }

           Func<NameValueCollection> formGetter;
           Func<NameValueCollection> queryStringGetter;

           ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);

           var form = formGetter();
           var queryString = queryStringGetter();

           var req = form.AllKeys.Any() ? form : queryString;

           if (!string.IsNullOrEmpty(this.ActionRegex))
           {
               foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
               {
                   if (key.Contains(":"))
                   {
                       if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
                       {
                           bool match = false;
                           for (int i = 0; i < key.Split(':').Count(); i++)
                           {
                               if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
                               {
                                   match = true;
                               }
                               else
                               {
                                   match = false;
                                   break;
                               }
                           }

                           if (match)
                           {
                               return !string.IsNullOrEmpty(req[key]);
                           }
                       }
                   }
                   else
                   {
                       if (Regex.IsMatch(key, this.Action + this.ActionRegex))
                       {
                           return !string.IsNullOrEmpty(req[key]);
                       }
                   }

               }
               return false;
           }
           else
           {
               return req.AllKeys.Contains(this.Action);
           }
       }
   }

享受無代碼氣味的多提交按鈕未來。

謝謝

HttpParamActionAttribute方法的修改版本,但有一個錯誤修復,不會導致過期/無效會話回發錯誤。 要查看這是否是您當前站點的問題,請在窗口中打開您的表單,然后在點擊SavePublish ,打開一個重復的窗口,然后注銷。 現在返回到您的第一個窗口並嘗試使用任一按鈕提交您的表單。 對我來說,我遇到了一個錯誤,因此此更改為我解決了該問題。 為了簡潔起見,我省略了一堆東西,但你應該明白這個想法。 關鍵部分是在屬性上包含ActionName並確保傳入的名稱是顯示表單的視圖的名稱

屬性類

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
    private readonly string actionName;

    public HttpParamActionAttribute(string actionName)
    {
        this.actionName = actionName;
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals(this.actionName, StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
}

控制器

[Authorize(Roles="CanAddContent")]
public ActionResult CreateContent(Guid contentOwnerId)
{
    var viewModel = new ContentViewModel
    {
        ContentOwnerId = contentOwnerId
        //populate rest of view model
    }
    return View("CreateContent", viewModel);
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult SaveDraft(ContentFormModel model)
{
    //Save as draft
    return RedirectToAction("CreateContent");
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult Publish(ContentFormModel model)
{
    //publish content
    return RedirectToAction("CreateContent");
}

查看

@using (Ajax.BeginForm("CreateContent", "MyController", new { contentOwnerId = Model.ContentOwnerId }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(x => x.ContentOwnerId)

    <!-- Rest of your form controls -->
    <input name="SaveDraft" type="submit" value="SaveDraft" />
    <input name="Publish" type="submit" value="Publish" />
}

對於每個提交按鈕,只需添加:

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

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

});

基於 mkozicki 的回答,我想出了一個有點不同的解決方案。 我仍然使用ActionNameSelectorAttribute但我需要處理兩個按鈕“保存”和“同步”。 他們做的幾乎一樣,所以我不想有兩個動作。

屬性

public class MultipleButtonActionAttribute : ActionNameSelectorAttribute
{        
    private readonly List<string> AcceptedButtonNames;

    public MultipleButtonActionAttribute(params string[] acceptedButtonNames)
    {
        AcceptedButtonNames = acceptedButtonNames.ToList();
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {            
        foreach (var acceptedButtonName in AcceptedButtonNames)
        {
            var button = controllerContext.Controller.ValueProvider.GetValue(acceptedButtonName);
            if (button == null)
            {
                continue;
            }                
            controllerContext.Controller.ControllerContext.RouteData.Values.Add("ButtonName", acceptedButtonName);
            return true;
        }
        return false;
    }
}

查看

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

控制器

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

我還想指出,如果動作做不同的事情,我可能會關注 mkozicki 的帖子。

我的 JQuery 方法使用擴展方法:

public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller
{
    RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);

    var onclick = string.Format("$('form').first().attr('action', '/{0}')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray()));
    var html = "<input type=\"submit\" value=\"" + value + "\" onclick=\"" + onclick + "\" />";

    return MvcHtmlString.Create(html);
}

你可以這樣使用它:

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

它呈現如下:

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

我為HtmlHelper創建了一個ActionButton方法。 它將在OnClick 事件中生成帶有一些javascript 的普通輸入按鈕,將表單提交給指定的控制器/操作。

你像那樣使用助手

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

這將生成以下 HTML

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

這是擴展方法代碼:

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# (C# 代碼只是從 VB DLL 中反編譯出來的,所以它可以得到一些美化...但是時間太短了 :-))

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

這些方法具有各種參數,但為了便於使用,您可以創建一些僅采用所需參數的重載。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM