คุณจัดการกับปุ่มส่งหลายปุ่มใน ASP.NET MVC Framework อย่างไร


733

มีวิธีง่ายๆในการจัดการกับปุ่มส่งหลายปุ่มจากแบบฟอร์มเดียวกันหรือไม่? ตัวอย่างเช่น:

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

ความคิดใด ๆ ที่จะทำเช่นนี้ใน ASP.NET Framework Beta? ตัวอย่างทั้งหมดที่ฉันทำมีปุ่มเพียงปุ่มเดียว


6
น่ากล่าวถึงการเริ่มต้นจากASP.NET Coreมีวิธีแก้ปัญหาง่ายกว่าที่อยู่ในรายการนี้
Steven Jeuris

คำตอบ:


629

นี่คือวิธีการแก้ปัญหาแอตทริบิวต์ที่ใช้ส่วนใหญ่สะอาดให้กับหลายปัญหาส่งปุ่มตามอย่างหนักในการโพสต์และความคิดเห็นจากมาร์ติน 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) { ... }

อัปเดต: หน้ามีดโกนจะให้ฟังก์ชั่นแบบเดียวกันนอกกรอบ สำหรับการพัฒนาใหม่มันอาจจะดีกว่า


3
ฉันพบวิธีนี้เพื่อการแต่งงานที่มีความสุขของเทคนิคอื่น ๆ ที่ใช้ ทำงานอย่างสมบูรณ์แบบและไม่ส่งผลกระทบต่อการแปล
เทรเวอร์

17
ทางออกที่ดี !! ไม่มีประโยชน์มากไปกว่าคำตอบที่ได้รับคะแนนสูงสุด
Sasha

11
ปัญหาของวิธีนี้คือถ้าคุณพยายามreturn View(viewmodel)ในกรณีที่โมเดลของคุณมีข้อผิดพลาดมันจะพยายามคืนมุมมองที่เรียกว่าSendหรือขึ้นอยู่กับชื่ออาร์กิวเมนต์ของคุณ
รองเท้า

15
@Shoe - เพิ่งพบสิ่งที่คล้ายกัน ให้แน่ใจว่าคุณระบุชื่อของมุมมองที่จะกลับอย่างชัดเจนหากคุณใช้วิธีนี้:return View("Index", viewModel)
ajbeaven

4
เพียงข้อมูลเราจำเป็นต้องเพิ่มระบบการสะท้อนกลับสำหรับ MethodInfo
Vignesh Subramanian

469

ตั้งชื่อปุ่มส่งของคุณจากนั้นตรวจสอบค่าที่ส่งในวิธีการควบคุมของคุณ:

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

28
เลวร้ายเกินไปคุณขึ้นอยู่กับข้อความที่แสดงบนปุ่มมันค่อนข้างยุ่งยากกับส่วนติดต่อผู้ใช้หลายภาษา
Omu

3
Switch / case ใช้งานได้กับค่าคงที่เท่านั้นดังนั้นเวอร์ชันที่แปลเป็นภาษาท้องถิ่นจะไม่สามารถใช้สวิตช์ / case ได้ คุณต้องเปลี่ยนไปใช้ถ้าอื่นหรือวิธีการจัดส่งอื่น ๆ
mlibby

10
คุณควรใช้ <button type = "submit" แทน <input type เนื่องจากค่าประเภท <button ไม่ใช่ข้อความ;) จากนั้นคุณสามารถมีสิ่งนี้: <button name = "mySubmitButton" type = "submit" value = "keyValue"> YourButtonText </button>
J4N

4
วิธีนี้จะทำงานกับการส่งแบบจำลองไปยังการกระทำแทนที่จะเป็นเพียงแค่ค่าการส่งได้อย่างไร
bizzehdee

2
ระวังอย่าตั้งชื่อปุ่ม "การกระทำ" หากคุณใช้ jQuery มันทำให้เกิดความขัดแย้งภายในไลบรารีที่แบ่ง URL การกระทำ
HotN

121

คุณสามารถตรวจสอบชื่อในการดำเนินการตามที่ได้รับการกล่าวถึง แต่คุณอาจพิจารณาว่านี่เป็นการออกแบบที่ดีหรือไม่ มันเป็นความคิดที่ดีที่จะพิจารณาความรับผิดชอบของการกระทำและไม่ได้ออกแบบคู่นี้มากเกินไปกับส่วน 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") %>

53
สิ่งนี้ใช้ได้เมื่อคุณไม่ต้องการข้อมูลฟอร์มเดียวกันสำหรับทุกปุ่มส่ง หากคุณต้องการข้อมูลทั้งหมดในรูปแบบทั่วไปกว่า Dylan Beattie เป็นวิธีที่จะไป มีวิธีที่สง่างามกว่านี้อีกไหม?
ดาน

3
เกี่ยวกับการนำเสนอด้วยภาพในกรณีนี้มีปุ่ม "ส่ง" ถัดจากปุ่ม "ยกเลิก" อย่างไร
Kris-I

1
ดีแลน: สำหรับปุ่มยกเลิกคุณไม่จำเป็นต้องส่งข้อมูลเลยและมันเป็นวิธีปฏิบัติที่ไม่ดีที่จะเชื่อมโยงตัวควบคุมกับองค์ประกอบ UI อย่างไรก็ตามหากคุณสามารถสร้างคำสั่ง "ทั่วไป" ได้มากกว่าหรือน้อยกว่าฉันคิดว่ามันใช้ได้ แต่ฉันจะไม่ผูกมันกับ "submitButton" เนื่องจากเป็นชื่อขององค์ประกอบ UI
Trevor de Koekkoek

1
@Kris: คุณสามารถวางตำแหน่งปุ่มของคุณด้วย CSS และพวกเขายังสามารถอยู่ใน 2 ส่วนของรูปแบบที่แตกต่างกัน
Trevor de Koekkoek

8
อย่างจริงจัง? ไม่ได้มีกลิ่นกับใครนอกจากฉัน?!

99

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

หากค่าใด ๆ ถูกโพสต์ไปยังหนึ่งในพารามิเตอร์เหล่านั้นนั่นหมายความว่าปุ่มนั้นเป็นค่าที่ถูกคลิก เว็บเบราว์เซอร์จะโพสต์ค่าสำหรับปุ่มเดียวที่คลิก ค่าอื่น ๆ ทั้งหมดจะเป็นโมฆะ

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

ฉันชอบวิธีนี้เนื่องจากไม่พึ่งพาคุณสมบัติค่าของปุ่มส่งซึ่งมีแนวโน้มที่จะเปลี่ยนแปลงได้มากกว่าชื่อที่กำหนดและไม่จำเป็นต้องเปิดใช้งานจาวาสคริปต์

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


2
หากใครพบคำถามเก่านี้เป็นคำตอบที่ชัดเจนถ้าคุณไม่ต้องการใช้องค์ประกอบ HTML5 <button> หากคุณไม่สนใจ HTML5 ให้ใช้ <button> พร้อมกับแอตทริบิวต์ value
Kugel

คุณจะทำอย่างไรถ้าสร้างการโทร ajax ในแบบฟอร์มนี้ ดูเหมือนว่า form.serialize () จะไม่รับชื่อปุ่มส่ง ..
mko

@ Kugel ถูกต้องนี่คือคำตอบที่สะอาดที่สุด ขอบคุณ
Arif YILMAZ

45

เพิ่งเขียนโพสต์เกี่ยวกับเรื่องนั้น: ปุ่มส่งหลายปุ่มพร้อม ASP.NET MVC :

โดยพื้นฐานแล้วแทนที่จะใช้ActionMethodSelectorAttributeฉันกำลังใช้ ActionNameSelectorAttributeซึ่งทำให้ฉันสามารถแกล้งทำเป็นชื่อแอ็คชันคืออะไรก็ได้ที่ฉันต้องการ โชคดีที่ActionNameSelectorAttributeไม่เพียง แต่ทำให้ฉันระบุชื่อการกระทำ แต่ฉันสามารถเลือกได้ว่าการกระทำปัจจุบันตรงกับคำขอหรือไม่

ดังนั้นจึงมีชั้นเรียนของฉัน (btw ฉันไม่ชอบชื่อมากเกินไป):

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

ดังที่คุณเห็นแอตทริบิวต์ไม่ต้องการให้คุณระบุอะไรเลย นอกจากนี้ชื่อของปุ่มจะถูกแปลโดยตรงไปยังชื่อเมธอด นอกจากนี้ (ฉันไม่ได้ลองสิ่งนั้น) สิ่งเหล่านี้ควรทำงานได้เหมือนปกติดังนั้นคุณสามารถโพสต์ข้อความใด ๆ ได้โดยตรง


1
สวย! ฉันคิดว่านี่เป็นทางออกที่ดีที่สุด มันกำจัดค่าของsubmitแท็กออกจากการพิจารณาซึ่งเหมาะอย่างยิ่งเนื่องจากเป็นคุณลักษณะ pure-UI ที่ไม่ควรมีผลต่อการควบคุมโฟลว์ แต่nameคุณสมบัติที่เป็นเอกลักษณ์ของแต่ละsubmitแท็กจะแปลโดยตรงเป็นวิธีการดำเนินการที่ไม่ต่อเนื่องบนคอนโทรลเลอร์ของคุณ
Kirk Woll

+1 สำหรับฉันมันเป็นทางออกที่ดีที่สุดสำหรับปัญหานี้ ตั้งแต่ฉันใช้มันฉันสังเกตเห็นว่าการจราจรผ่าน HttpParamActionAttribut จำนวนมาก แต่เมื่อเทียบกับสิ่งอื่น ๆ ทั้งหมดที่ Asp.Net MVC ต้องทำในขณะที่ประมวลผลคำขอเป็นที่ยอมรับโดยสิ้นเชิง ในการแฮ็คเท่านั้นที่ฉันต้องทำคือใส่ 'การกระทำ' ที่ว่างเปล่าไว้ในตัวควบคุมของฉันเพื่อป้องกัน Resharper เตือนฉันว่าการกระทำ 'ไม่มี' ขอบคุณมาก!
ซามูเอล

ฉันตรวจทานโซลูชันทั้งหมดและยอมรับว่านี่เป็นโซลูชันที่เรียบง่ายและสง่างาม bc ที่ยอดเยี่ยมไม่มีคำสั่งแบบมีเงื่อนไขและมีประสิทธิภาพซึ่งคุณสามารถกำหนดการกระทำของคอนโทรลเลอร์ใหม่เมื่อคุณมีปุ่มใหม่ เรียกชั้นเรียนของฉัน MultiButtonActionHandler FYI ;-)
ejhost

36

มันสั้นและห้องชุด:

มันตอบโดย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
}

โชคดี.


น่ากลัว สิ่งที่ฉันเคยทำในเว็บฟอร์ม ไชโยเพื่อน
djack109

ง่ายกว่าคำตอบยอดนิยมมาก! ขอบคุณ!
pabben

35

ฉันขอแนะนำให้ผู้ที่สนใจได้ดูวิธีการแก้ปัญหาของ Maarten Balliauwได้ดูที่วิธีการแก้ปัญหาฉันคิดว่ามันสวยงามมาก

ในกรณีที่การเชื่อมโยงหายไปมันใช้แอMultiButtonททริบิวต์ที่ใช้กับแอคชั่นควบคุมเพื่อระบุว่าคลิกปุ่มที่แอคชั่นนั้นเกี่ยวข้อง


นี่คือวิธีการแก้ปัญหาที่เราใช้ตอนนี้และมันประณีตมาก มันเป็น MVC 2 เท่านั้นใช่มั้ย
Simon Keep

นี่คือสิ่งที่สวยงาม! ฉันไม่เคยเห็นสิ่งนี้มาก่อน! ในขณะที่ฉันยอมรับว่าคุณอาจต้องการออกแบบวิธีแก้ปัญหาที่ใช้การส่งหลายครั้งเพื่อใช้เพียงปุ่มเดียว แต่ฉันอยู่ในจุดที่ฉันขัดขวางและต้องทำสิ่งนี้ คำตอบนี้ควรจะชนะ!
Rikon

นี่เป็นทางออกที่ดี สะอาดมาก
Arnej65

ลองใช้วิธีนี้และไม่สามารถใช้งานได้ใน MVC3 การเปลี่ยนแปลงของผู้โหวตโหวต # 1 เหมาะกับฉัน
Scott Lawrence

สั้นและหวาน .. แต่ไม่ใช่สำหรับ mvc 3+
Piotr Kula

21

คุณควรจะสามารถตั้งชื่อปุ่มต่าง ๆ และให้คุณค่ากับมัน จากนั้นแมปชื่อนี้เป็นอาร์กิวเมนต์ของการกระทำ หรือมิฉะนั้นให้ใช้ลิงค์การกระทำ 2 แบบแยกกันหรือ 2 รูปแบบ


เท่าที่ผ่านมาวิธีทำความสะอาดที่ง่ายที่สุดและง่ายที่สุดที่ฉันเคยเห็นมา
Jason Evans

13

คุณสามารถเขียน:

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

จากนั้นในหน้าตรวจสอบว่าชื่อ == "ส่ง" หรือชื่อ == "ยกเลิก" ...


1
แม้ว่านี่จะใช้งานได้ แต่ฉันคิดว่ามันผิดที่จะมีองค์ประกอบสองอย่างที่มีชื่อเหมือนกัน
Péter

1
มันไม่จำเป็นผิด ขึ้นอยู่กับว่าคุณใช้อินพุตอย่างไร คุณสามารถมีองค์ประกอบหลายอย่างที่มีชื่อเดียวกันและคาดหวังว่าจะได้รับข้อมูลจำนวนมาก (นี่คือวิธีที่ radiobuttons และช่องทำเครื่องหมายทำงาน) แต่ใช่ถ้าคุณใช้วิธีนี้เป็นเพราะคุณกำลังทำ "ผิด" ... นั่นคือเหตุผลที่ฉันใส่ "คุณทำได้" แต่ไม่ใช่ "คุณควร": P
Ironicnet

12

สิ่งที่ฉันไม่ชอบเกี่ยวกับ ActionSelectName คือ IsValidName ถูกเรียกใช้สำหรับทุกวิธีการดำเนินการในตัวควบคุม ฉันไม่รู้ว่าทำไมมันใช้งานแบบนี้ ฉันชอบวิธีแก้ปัญหาที่ทุกปุ่มมีชื่อแตกต่างกันไปตามสิ่งที่มันทำ แต่ฉันไม่ชอบความจริงที่ว่าคุณต้องมีพารามิเตอร์จำนวนมากในวิธีการดำเนินการเป็นปุ่มในรูปแบบ ฉันได้สร้าง enum สำหรับปุ่มทุกประเภทแล้ว:

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

ตัวกรองจะค้นหาชื่อปุ่มในข้อมูลแบบฟอร์มและหากชื่อปุ่มตรงกับประเภทของปุ่มที่กำหนดไว้ใน enum มันจะค้นหาพารามิเตอร์ 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" />

11

นี่คือสิ่งที่ดีที่สุดสำหรับฉัน:

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

ฉันได้รับค่า null สำหรับ onDelete และ onSave ในวิธีการควบคุม คุณรู้ไหมว่าทำไม?
Diganta Kumar

อย่างใดอย่างหนึ่งจะไม่เป็นโมฆะถ้าคุณคลิกที่ปุ่มตาม คุณคลิกปุ่มใดเพื่อรับค่า Null?
Sergey

11

ฉันเจอปัญหานี้แล้ว แต่พบวิธีแก้ปัญหาที่สมเหตุสมผลมากกว่าโดยการเพิ่ม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

    }

}

นี่คือทางออกที่เราเลือกใช้สำหรับแอพพลิเคชั่นเว็บง่ายๆที่เราต้องการฟังก์ชั่น ASP.NET WebForms แต่ภายใน MVC
BrandonG

10

หากคุณไม่มีข้อ จำกัด ในการใช้ 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


9

หากเบราว์เซอร์ของคุณรองรับการทำงานของแอททริบิวสำหรับปุ่มอินพุต (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") />

}

ลองดูคำตอบของฉันด้านล่างมันไม่ได้ขึ้นอยู่กับข้อกำหนดร่าง คำตอบของคุณอนุญาตให้มีความเป็นไปได้ที่จะมี URL การกระทำที่แตกต่างกันซึ่งฉันไม่ชอบ
Tom Hofman

9

มีสามวิธีที่คุณสามารถแก้ไขปัญหาข้างต้นได้

  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” ดูรหัสด้านล่าง ฟังก์ชั่นเหล่านี้จะทำการโทร Ajax โดยใช้ JQUERY หรือกรอบงานอื่น ๆ แต่ละฟังก์ชั่นเหล่านี้ถูกผูกไว้กับเหตุการณ์“ 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” ในคลาสนี้เราได้สร้างคุณสมบัติ "ชื่อ" แบบง่าย

นอกจากนี้เรายังต้องแทนที่ฟังก์ชั่น“ IsValidName” ซึ่งจะคืนค่าจริงหรือ flase ฟังก์ชั่นนี้เป็นที่ที่เราเขียนลอจิกว่าจะต้องมีการดำเนินการหรือไม่ ดังนั้นหากฟังก์ชันนี้คืนค่าเป็นจริงการดำเนินการจะถูกดำเนินการหรือไม่เช่นนั้น

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” มีข้อมูลทั้งหมดที่โพสต์จากแบบฟอร์ม ดังนั้นก่อนค้นหาค่า“ ชื่อ” และหากพบในคำขอ HTTP จะส่งคืนจริงหรือมิฉะนั้นจะส่งกลับเท็จ

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

7

David Findley เขียนเกี่ยวกับ 3 ตัวเลือกต่าง ๆ ที่คุณมีสำหรับการทำสิ่งนี้บนเว็บบล็อก ASP.Net ของเขา

อ่านบทความหลายปุ่มในรูปแบบเดียวกันเพื่อดูวิธีแก้ไขปัญหาของเขาและข้อดีและข้อเสียของแต่ละปุ่ม IMHO เขานำเสนอทางออกที่ยอดเยี่ยมซึ่งใช้ประโยชน์จากคุณลักษณะที่คุณตกแต่งการกระทำของคุณด้วย


7

นี่เป็นเทคนิคที่ฉันใช้และฉันยังไม่เห็นที่นี่ การเชื่อมโยง (โพสต์โดย Saajid อิสมาอิล) ที่เป็นแรงบันดาลใจการแก้ปัญหานี้คือ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;
         }
    }
}

ดูเหมือนว่าโซลูชัน Ironicnet ที่ให้ไว้
Kris van der Mast

คล้ายกันอย่างแน่นอน แต่สิ่งนี้แสดงให้เห็นทั้งการแปลและตัวควบคุมรหัสซึ่งเป็นสิ่งที่ฉันไม่เห็นทำด้วยวิธีนี้ในหัวข้อนี้ ฉันพบกระทู้นี้ในขณะที่มองหาวิธีการทำและต้องการบันทึกสิ่งที่ฉันเกิดขึ้นกับใครก็ตามที่อาจอยู่ในเรือลำเดียวกัน
mlibby

1
ในความเป็นจริงมันไม่เหมือนกับของ Ironicnet มากกว่านั้น เขาใช้<input>องค์ประกอบ ฉันใช้<button>ซึ่งจำเป็นต้องใช้ในการแปลโดยไม่ต้องมีแอตทริบิวต์ค่าตัวแปร
mlibby

7

สคริปต์นี้อนุญาตให้ระบุแอตทริบิวต์ data-form-action ซึ่งจะทำงานเป็นแอตทริบิวต์ formaction HTML5 ในเบราว์เซอร์ทั้งหมด (ในลักษณะที่ไม่เป็นการรบกวน):

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

แบบฟอร์มที่มีปุ่มจะถูกโพสต์ไปยัง URL ที่ระบุในแอตทริบิวต์ data-form-action:

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

ต้องใช้ jQuery 1.7 สำหรับรุ่นก่อนหน้านี้คุณควรใช้แทนlive()on()


6

ต่อไปนี้เป็นวิธีส่วนขยายที่ฉันเขียนเพื่อจัดการกับปุ่มรูปภาพและ / หรือข้อความหลายปุ่ม

นี่คือ 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;
        }
    }
}

หมายเหตุ:Submit_สำหรับปุ่มข้อความที่คุณมีคำนำหน้าชื่อด้วย ฉันชอบวิธีนี้เพราะมันหมายความว่าคุณสามารถเปลี่ยนค่าข้อความ (แสดง) โดยไม่ต้องเปลี่ยนรหัส ซึ่งแตกต่างจากSELECTองค์ประกอบที่เป็นINPUTปุ่มมีเพียง 'ค่า' และไม่มีการแยกต่างหากแอตทริบิวต์ 'ข้อความ' ปุ่มของฉันพูดสิ่งต่าง ๆ ภายใต้บริบทที่แตกต่าง - แต่แมปไปที่ 'คำสั่ง' เดียวกัน == "Add to cart"ผมชอบมากแยกชื่อด้วยวิธีนี้กว่าที่มีการสำหรับ


ฉันชอบการตรวจสอบชื่อเป็นทางเลือกเพราะคุณไม่สามารถตรวจสอบค่าเช่น คุณมีรายการและแต่ละรายการมีปุ่ม "ลบ"
สูงสุด

6

ฉันมีตัวแทนไม่เพียงพอที่จะแสดงความคิดเห็นในสถานที่ที่ถูกต้อง แต่ฉันใช้เวลาตลอดทั้งวันในเรื่องนี้ดังนั้นต้องการแบ่งปัน

ขณะที่พยายามที่จะใช้ "MultipleButtonAttribute" การแก้ปัญหาไม่ถูกต้องจะกลับมาValueProvider.GetValue(keyValue)null

ปรากฎว่าฉันอ้างอิง System.Web.MVC เวอร์ชัน 3.0 เมื่อมันควรจะเป็น 4.0 (ชุดประกอบอื่น ๆ คือ 4.0) ฉันไม่รู้ว่าทำไมโครงการของฉันจึงไม่อัพเกรดอย่างถูกต้องและฉันก็ไม่มีปัญหาที่ชัดเจนอื่น ๆ

ดังนั้นหากคุณActionNameSelectorAttributeไม่ทำงาน ... ตรวจสอบว่า


6

ฉันมาช้าไปงานเลี้ยง แต่ที่นี่จะไป ... การดำเนินการของฉันยืมมาจาก @mkozicki แต่ต้องใช้สตริง hardcoded น้อยกว่าที่จะผิด กรอบ 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;
    }
}

แม้ว่านี่จะเป็นวิธีการที่ดี แต่คุณจะไม่สามารถใช้ตัวสร้างโมเดล mvc ในตัวได้เนื่องจากมันจะใช้ปุ่ม "ชื่อ" แอตทริบิวต์
ooXei1sh

วัตถุประสงค์ของการแก้ปัญหานี้คือการหลีกเลี่ยงการกำหนดเส้นทางการโพสต์ MVC โปรดอธิบายการปรับปรุง
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>

    }

นี่เป็นอีกลิงค์ที่มีประโยชน์อธิบายวิธีการโพสต์แบบต่างๆ
หิมาลัย Garg

5

ฉันพยายามสังเคราะห์วิธีแก้ปัญหาทั้งหมดและสร้างแอตทริบิวต์ [ButtenHandler] ซึ่งทำให้ง่ายต่อการจัดการกับปุ่มหลายปุ่มในแบบฟอร์ม

ผมได้อธิบายไว้ใน CodeProject หลายแปรปุ่ม (localizable) ฟอร์มใน 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);
}

ขอให้สังเกตว่าชื่อของปุ่มตรงกับชื่อของวิธีการดำเนินการ บทความนี้ยังอธิบายถึงวิธีการมีปุ่มที่มีค่าและปุ่มที่มีดัชนี


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

คุณอาจไม่ได้ตระหนักถึงมัน แต่คำตอบเดียวกันนี้ได้โพสต์ในคำถามนี้ไปแล้วสองสามครั้ง
Andrew Barber

2
นอกจากนี้คุณดูเหมือนโพสต์คำตอบที่มีเพียงรหัสโดยไม่มีคำอธิบาย คุณจะพิจารณาเพิ่มคำบรรยายเพื่ออธิบายว่าทำไมรหัสจึงใช้งานได้และอะไรทำให้เป็นคำตอบของคำถาม สิ่งนี้จะเป็นประโยชน์กับผู้ที่ถามคำถามและใครก็ตามที่เข้ามา
Andrew Barber

2
แน่นอนว่ามันใช้งานได้ดี แต่คำตอบนั้นได้รับมาจากคนอื่นมานานแล้ว และพวกเขารวมคำอธิบายเกี่ยวกับสาเหตุที่ใช้งานได้ด้วย
Andrew Barber

5

นี่คือวิธีที่ดีที่สุดที่ฉันได้พบ:

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

เพลิดเพลินไปกับอนาคตของปุ่มส่งแบบไม่มีกลิ่นหลายรหัส

ขอบคุณ


ลิงก์ใช้งานไม่ได้ในขณะนี้เป็นรุ่นที่เก็บถาวรที่ใกล้เคียงที่สุดที่ฉันหาได้: web.archive.org/web/20110706230408/http://blogs.sonatribe.com/…
Ian Kemp

สวัสดีเอียน - ขอบคุณที่ขุดออกมา - ฉันโพสต์ไว้ที่นี่: iwayneo.blogspot.co.uk/2013/10/25

4

รุ่น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" />
}

3

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')" >


3

จากคำตอบ 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


1

ฉันได้สร้างActionButton แล้ววิธีการสำหรับ HtmlHelper มันจะสร้างปุ่มอินพุตปกติพร้อมกับจาวาสคริปต์ในเหตุการณ์ OnClickที่จะส่งแบบฟอร์มไปยังคอนโทรลเลอร์ / การดำเนินการที่ระบุ

คุณใช้ผู้ช่วยอย่างนั้น

@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 # นั้นเพิ่งถูกคอมไพล์จาก 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));
}

วิธีการเหล่านี้มีพารามิเตอร์ต่าง ๆ แต่เพื่อความสะดวกในการใช้งานคุณสามารถสร้างเกินพิกัดที่ใช้เพียงแค่พารามิเตอร์ที่คุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.