質問

同じフォームから複数の送信ボタンを処理する簡単な方法はありますか?例:

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

ASP.NET Framework ベータ版でこれを行う方法はありますか?私がグーグルで検索したすべての例には、単一のボタンがあります。

役に立ちましたか?

解決

Maartin Balliauw

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

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

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

        return isValidName;
    }
}

カミソリ:

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

また、<!> quot; Cancel <!> quot;の場合、通常はフォームを処理せずに新しいURLに移動します。この場合、フォームを送信する必要はなく、リンクが必要です。

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

イーロンは、次のようにすることができると提案しています。

複数のボタンがある場合は、各ボタンに名前を付けることで、それらを区別できます。

<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 ...)
{ ... }

これらのパラメーターの1つに値が投稿された場​​合、それはそのボタンがクリックされたものであることを意味します。Webブラウザは、 1つ クリックされたボタン。他のすべての値は null になります。

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

この方法は、割り当てられた名前よりも変更される可能性が高い送信ボタンの value プロパティに依存せず、JavaScript を有効にする必要がないため、気に入っています。

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

それについての記事を書いただけです: ASP.NET MVCを使用した複数の送信ボタン

基本的に、ActionMethodSelectorAttributeを使用する代わりに、私は 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" />
<% } %> 

および2つのメソッドを持つコントローラー

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

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

ご覧のとおり、この属性では何も指定する必要はありません。また、ボタンの名前はメソッド名に直接変換されます。さらに(私は!#8217; tを試してみました)これらは通常のアクションとしても機能するはずなので、それらのいずれかに投稿できます 直接。

私は、関係者 Maarten Balliauwのソリューションをご覧ください。とてもエレガントだと思います。

リンクが消える場合、コントローラーアクションに適用されるMultiButton属性を使用して、そのアクションが関連するボタンクリックを示します。

それは短くスイートです:

  

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
}

がんばって。

ボタンに名前を付けて値を与えることができるはずです。次に、この名前をアクションへの引数としてマップします。または、2つの個別のアクションリンクまたは2つのフォームを使用します。

次のように書くことができます:

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

そして、ページで名前が== <!> quot; Send <!> quot;かどうかを確認します。またはname == <!> quot; Cancel <!> quot; ...

ActionSelectNameが気に入らない点は、IsValidNameがコントローラーのすべてのアクションメソッドに対して呼び出されることです。なぜこのように機能するのかわかりません。私はすべてのボタンの機能に応じてボタンの名前が異なるソリューションが好きですが、アクションメソッドにはフォームのボタンと同じ数のパラメーターが必要であるという事実が好きではありません。すべてのボタンタイプの列挙型を作成しました:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

ActionSelectNameの代わりに、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;
            }
        }
    }
}

フィルターは、フォームデータでボタン名を検索し、ボタン名が列挙で定義されたボタンタイプのいずれかに一致する場合、アクションパラメーターの中から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" />

これが私に最適なものです:

<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

ブラウザが入力ボタンの属性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

    }

}

上記の問題を解決する方法は3つあります

  1. HTMLの方法
  2. Jqueryの方法
  3. <!>#8220; ActionNameSelectorAttribute <!>#8221;方法

以下は、3つのアプローチすべてを実証的な方法で要約したビデオです。

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

HTMLの方法:-

HTMLの方法では、2つのフォームを作成し、<!>#8220; Submit <!>#8221;を配置する必要があります。各フォーム内のボタン。そして、すべてのフォーム<!>#8217;のアクションは、異なる/それぞれのアクションを指します。最初のフォームが<!>#8220; Action1 <!>#8221;に投稿している以下のコードを見ることができます。 2番目のフォームは<!>#8220; Action2 <!>#8221;に投稿します。 <!>#8220; Submit <!>#8221;ボタンをクリックします。

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

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

Ajaxの方法:-

Ajaxの愛好家の場合、この2番目のオプションはあなたをより興奮させます。 Ajaxの方法では、2つの異なる関数<!>#8220; Fun1 <!>#8221;を作成できます。および<!>#8220; Fun1 <!>#8221; 、以下のコードを参照してください。これらの関数は、JQUERYまたはその他のフレームワークを使用してAjax呼び出しを行います。これらの各機能は、<!>#8220; Submit <!>#8221;にバインドされています。 button <!>#8217; s <!>#8220; OnClick <!>#8221;イベント。これらの各関数は、それぞれのアクション名を呼び出します。

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

<!>#8220; ActionNameSelectorAttribute <!>#8221;:-を使用して

これは素晴らしい、きれいなオプションです。 <!>#8220; ActionNameSelectorAttribute <!>#8221;実行可能なアクションを決定する意思決定ロジックを記述できる単純な属性クラスです。

最初のことはHTMLで、サーバー上でそれらを識別するために適切な名前<!>#8217; sを送信ボタンに配置する必要があります。

<!>#8220; Save <!>#8221;および<!>#8220; Delete <!>#8221;ボタン名に。また、コントローラー名<!>#8220; Customer <!>#8221;特定のアクション名ではありません。アクション名は<!>#8220; ActionNameSelectorAttribute <!>#8221;によって決定されることを期待しています。

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

したがって、送信ボタンをクリックすると、最初に<!>#8220; ActionNameSelector <!>#8221;がヒットします。属性を指定し、どの送信が実行されるかに応じて、適切なアクションを呼び出します。

ここに画像の説明を入力

最初のステップは、<!>#8220; ActionNameSelectorAttribute <!>#8221;を継承するクラスを作成することです。クラス。このクラスでは、単純なプロパティ<!>#8220; Name <!>#8221;を作成しました。

<!>#8220; IsValidName <!>#8221;もオーバーライドする必要があります。 trueまたはflaseを返す関数。この関数は、アクションを実行する必要があるかどうかに関係なくロジックを記述する場所です。したがって、この関数が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;

        }
    }

上記の関数の中心は、以下のコードにあります。 <!>#8220; ValueProvider <!>#8221;コレクションには、フォームから投稿されたすべてのデータが含まれます。そのため、最初に<!>#8220; Name <!>#8221;を検索します。値。HTTPリクエストで見つかった場合はtrueを返し、そうでない場合はfalseを返します。

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

この属性クラスは、それぞれのアクションとそれぞれの<!>#8220; Name <!>#8221;で装飾できます。値を提供できます。したがって、送信がこのアクションにヒットし、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;
         }
    }
}

このスクリプトにより、すべてのブラウザーでHTML5 formaction属性として機能するdata-form-action属性を指定できます(控えめな方法で):

$(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()を使用する必要があります。

これは、複数の画像やテキストボタンを処理するために作成した拡張メソッドです。

画像ボタンの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_で始まる名前を探し、その後からコマンドを抽出します。 「コマンド」を決定するロジックを抽象化しているため、サーバー側のコードを変更せずに、クライアントで画像+テキストボタンを切り替えることができます。

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

注:テキストボタンの場合、名前の前にSELECTを付ける必要があります。コードを変更せずにテキスト(表示)値を変更できるため、この方法が好ましいです。 INPUT要素とは異なり、== "Add to cart"ボタンには「値」のみがあり、個別の「テキスト」属性はありません。私のボタンは、異なるコンテキストで異なることを言いますが、同じ「コマンド」にマップします。 <=>をコーディングするよりも、この方法で名前を抽出する方がずっと好きです。

正しい場所にコメントするのに十分な担当者がいないが、私はこれに一日中費やしたので共有したい。

<!> quot; MultipleButtonAttribute <!> quot;を実装しようとしています。解決策ValueProvider.GetValue(keyValue)は誤ってnullに戻ってきます。

System.Web.MVCバージョン3.0を4.0にすべきだったときに参照していたことが判明しました(他のアセンブリは4.0です)。私のプロジェクトが正しくアップグレードされなかった理由がわかりません。他に明らかな問題はありませんでした。

したがって、ActionNameSelectorAttributeが機能しない場合は...確認してください。

パーティーにはかなり遅れていますが、ここに行きます... 私の実装は@mkozickiを借用していますが、ハードコーディングされた文字列を少なくすればエラーが発生します。 フレームワーク4.5以降が必要。基本的に、コントローラーメソッド名はルーティングのキーにする必要があります。

マークアップ。ボタン名は、&quot; action:[controllerMethodName]&quot;

でキー設定する必要があります

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

すべてのソリューションを統合して、フォーム上の複数のボタンを簡単に処理できる [ButtenHandler] 属性を作成しようとしました。

CodeProjectで説明しました ASP.NET MVC の複数のパラメーター化された (ローカライズ可能な) フォーム ボタン.

このボタンの単純なケースを処理するには:

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

コード臭のないマルチ送信ボタンの未来をお楽しみください。

ありがとう

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

    }

HttpParamActionAttribute メソッドのバージョンを修正しましたが、期限切れ/無効なセッションポストバックでエラーが発生しないというバグ修正があります。これが現在のサイトに問題があるかどうかを確認するには、ウィンドウでフォームを開き、 Save または Publish をクリックする直前に、複製ウィンドウを開き、ログアウト。最初のウィンドウに戻り、いずれかのボタンを使用してフォームを送信してください。私にとってエラーが発生したので、この変更はその問題を解決します。簡潔にするために多くのものを省略しますが、あなたはそのアイデアを得る必要があります。重要な部分は、属性に 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" />
}

拡張メソッドを使用した私の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')" >

送信ボタンごとに次を追加します。

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

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

});

mkozickiの回答に基づいて、少し異なる解決策を考え出しました。まだ ActionNameSelectorAttribute を使用していますが、「保存」と「同期」の2つのボタンを処理する必要がありました。それらはほとんど同じであるため、2つのアクションを実行する必要はありませんでした。

属性

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の投稿に従うことを指摘したいと思います。

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帰属
所属していません StackOverflow
scroll top