2010-10-17 24 views
8

Tôi đang cố gắng ràng buộc một danh sách là một phần của mô hình chế độ xem lớn hơn mà không cần sử dụng một trình kết nối mô hình tùy chỉnh. Khi tôi sử dụng mẫu trình chỉnh sửa để tạo danh sách các yếu tố đầu vào, tên được tạo không ở định dạng chính xác cho trình kết nối mặc định hoạt động.Liên kết mô hình MVC ASP.NET IList trong Mẫu biên tập

Thay vì các mục [3] .Id như tôi mong đợi nó là Mục. [3] .Id. Nếu tôi xây dựng danh sách mà không có mẫu trình soạn thảo, nó hoạt động như mong đợi.

Tôi có đang làm điều gì đó hiển nhiên không đúng hay đây chỉ là một dấu nháy đơn của Html.Hidden và Html.TextBox?

public class ItemWrapper 
{ 
    [UIHint("ItemList")] 
    public IList<Item> Items { get; set; } 
} 

public class Item 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public int Value { get; set; } 
} 

index.aspx

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 

    <h2>Index</h2> 

    <% using(Html.BeginForm()) 
    {%> 
    <%:Html.EditorFor(m => m.Items) %> 
    <%}%> 
</asp:Content> 

ItemList.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<Mvc2Test.Models.Item>>" %> 

<h4>Asset Class Allocation</h4> 
<% if(Model.Count > 0) { %> 
<table> 
    <tbody> 
    <% for(int i = 0; i < Model.Count; i++) 
    {%> 
     <tr> 
     <td><%: Model[i].Name%></td> 
     <td> 
      <%: Html.HiddenFor(m => m[i].Id) %> 
      <%: Html.TextBoxFor(m => m[i].Value) %> 
     </td> 
     </tr> 
    <%}%> 
    </tbody> 
</table> 
<% 
}%> 

Output

<tr> 
    <td>Item 4</td> 
    <td> 
    <input id="Items__3__Id" name="Items.[3].Id" type="hidden" value="f52a1f57-fca8-4bc5-a746-ee0cef4e05c2" /> 
    <input id="Items__3__Value" name="Items.[3].Value" type="text" value="40" /> 
    </td> 
</tr> 

Sửa (Action Method)

public ActionResult Test() 
{ 
    return View(
    new ItemWrapper 
    { 
     Items = new List<Item> 
     { 
     { new Item { Id = Guid.NewGuid(), Name = "Item 1", Value = 10 } }, 
     { new Item { Id = Guid.NewGuid(), Name = "Item 2", Value = 20 } }, 
     { new Item { Id = Guid.NewGuid(), Name = "Item 3", Value = 30 } }, 
     { new Item { Id = Guid.NewGuid(), Name = "Item 4", Value = 40 } } 
     } 
    }); 
} 

Chỉnh sửa # 2

HttpPost Action

[HttpPost] 
public ActionResult Test(ItemWrapper w) 
{ 
    if(w.Items == null) 
     Response.Write("Items was null"); 
    else 
     Response.Write("Items found " + w.Items.Count.ToString()); 
    return null; 
} 

index.aspx

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 

<h4>Does Not Work</h4> 
<% using(Html.BeginForm("Test", "Home")) 
{%> 
     <%:Html.EditorFor(m => m.Items) %> 
     <input type="submit" value-"Go" /> 
<%}%> 

<h4>Does Work</h4> 
     <% using(Html.BeginForm("Test", "Home")) 
     {%> 
    <table> 
     <tbody> 
      <% for(int i = 0; i < Model.Items.Count; i++) 
      {%> 
      <tr> 
       <td><%: Model.Items[i].Name%></td> 
       <td> 
        <%: Html.HiddenFor(m => Model.Items[i].Id) %> 
        <%: Html.TextBoxFor(m => Model.Items[i].Value) %> 
       </td> 
      </tr> 
      <%}%> 
     </tbody> 
    </table> 
      <input type="submit" value-"Go" /> 
     <%}%> 

</asp:Content> 

Trả lời

7

tôi đã hiểu vấn đề của bạn, và tôi rất tốt có thể có một giải pháp quá :)!

Trước tiên, hãy để tôi giải thích cho bạn những gì tôi đã học bằng cách kiểm tra framework's source code (bạn nên kiểm tra mã nguồn của dự án nguồn mở để hiểu rõ hơn cách hoạt động của một số thứ nhất định).

1-) Khi sử dụng đơn giản mạnh mẽ gõ người giúp đỡ html (tức là tất cả Html.xxxFor (...) phương pháp trừ EditorForDisplayFor), trong biểu thức lambda xác định tài sản của mô hình để render, tên của phần tử html tạo ra là tương đương với bất cứ chuỗi sau "mô hình =>", trừ những gì đến trước khi "=>", có nghĩa là để nói:

  • chuỗi "mô hình" nếu mô hình này là một bộ sưu tập
  • hoặc chuỗi "mô hình. "(lưu ý" . "ở cuối) nếu không.

Vì vậy, ví dụ này:

<%: Html.TextBoxFor(m=>m.OneProperty.OneNestedProperty)%> 

sẽ tạo ra sản lượng này html:

<input type="text" name="OneProperty.OneNestedProperty" ../> 

Và đây:

<%: Html.TextBoxFor(m=>m[0].OneProperty.OneNestedProperty)%> 

sẽ tạo này:

<input type="text" name="[0].OneProperty.OneNestedProperty" ../> 

==> Điều này giải thích một phần lý do tại sao bạn có đầu ra html "lạ" này khi sử dụng EditorFor.

2-) Khi sử dụng phức tạp mạnh mẽ gõ người giúp đỡ (EditorFor và DisplayFor), các quy tắc trước tương tự được áp dụng bên trong xem một phần liên quan (ItemList.ascx trong trường hợp của bạn), và trong Ngoài ra, tất cả các phần tử html được tạo sẽ là có tiền tố theo sau "==>", như được giải thích trong 1-).

Tiền tố ở đây là "Items", bởi vì bạn có điều này theo quan điểm đánh máy của bạn (index.aspx):

<%:Html.EditorFor(m => m.Items) %> 

==> Đây hoàn toàn giải thích đầu ra, và tại sao mặc định chất kết dính không làm việc nữa với danh sách các mục

các giải pháp sẽ là nghỉ xuống bạn ItemWrapper tham số trong [HttpPost] phương pháp, thành thuộc tính của mình, và sau đó sử dụng Bind Thuộc tính với Prefix tham số của mình cho mỗi tài sản phức tạp, như thế này:

[HttpPost] 
    public string Index(string foo,[Bind(Prefix = "Items.")]IList<Item> items) 
    { 
     return "Hello"; 
    } 

(giả rằng ItemWrapper cũng có một thuộc tính đơn giản có tên là Foo của loại chuỗi)

Để tránh xung đột, khi liệt kê các thuộc tính trong phương pháp hậu, tôi khuyên bạn nên đặt tên các tham số theo ea ch tên của tài sản (không có mather trường hợp) như tôi đã làm.

Hy vọng điều này sẽ hữu ích!

+0

Vì vậy, nó thực sự là một điều không minh bạch trong cách MVC tạo ra các tên trường. Chế độ xem một phần không tính đến mô hình đó là một bộ sưu tập khi tạo tên trường. Tôi đoán nếu các mục.được tạo ở cấp chế độ xem thay vì cấp chế độ xem một phần thì có thể không có cách nào tốt để khắc phục nó. Cảm ơn. –

+0

kondotine: âm thanh như một lỗi mvc asp.net, có ai chưa báo cáo không? – Wout

+0

Ok, đã tự báo cáo: http://aspnet.codeplex.com/workitem/7711, vui lòng bỏ phiếu cho sửa lỗi này! – Wout

-1

Một giải pháp lười biếng hơn là chỉ sử dụng jQuery để "khắc phục" các trường hợp thuộc loại này. Chỉ cần chạy các chức năng sau đây sau khi các trang (hoặc trang từng phần) tải:

function makeHiddenInputBindable() { 
    $('input[type="hidden"]').each(
     function (i) { 
      $(this).attr('name', function() { 
       return this.name.replace(/\.\[/g, "["); 
      }) 
     } 
    ); 
} 
+1

jQuery không nên được sử dụng như một cái nạng để làm lại HTML bị hỏng. Sửa chữa nó ở phía máy chủ. –