2010-01-29 25 views
18

tôi đang làm việc với ASP.NET MVC2 RC và không thể tìm ra cách để có được sự trợ giúp HTML, TextBoxfor để làm việc với một ViewModel mẫu. Khi được sử dụng trên trang chỉnh sửa, dữ liệu sẽ không được lưu khi UpdateModel() được gọi trong bộ điều khiển. Tôi đã lấy các ví dụ mã sau đây từ ứng dụng NerdDinner.Sử dụng ViewModel mẫu với MVC 2 Typed mạnh HTML Helpers

Edit.aspx

<%@ Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.DinnerFormViewModel>" %> 
... 
<p> 
    // This works when saving in controller (MVC 1) 
    <label for="Title">Dinner Title:</label> 
    <%= Html.TextBox("Title", Model.Dinner.Title) %> 
    <%= Html.ValidationMessage("Title", "*") %> 
</p> 
<p> 
    // This does not work when saving in the controller (MVC 2) 
    <label for="Title">Dinner Title:</label> 
    <%= Html.TextBoxFor(model => model.Dinner.Title) %> 
    <%= Html.ValidationMessageFor(model=> model.Dinner.Title) %> 
</p> 

DinnerController

// POST: /Dinners/Edit/5 

[HttpPost, Authorize] 
public ActionResult Edit(int id, FormCollection collection) { 

    Dinner dinner = dinnerRepository.GetDinner(id); 

    if (!dinner.IsHostedBy(User.Identity.Name)) 
     return View("InvalidOwner"); 

    try { 
     UpdateModel(dinner); 

     dinnerRepository.Save(); 

     return RedirectToAction("Details", new { id=dinner.DinnerID }); 
    } 
    catch { 
     ModelState.AddModelErrors(dinner.GetRuleViolations()); 

     return View(new DinnerFormViewModel(dinner)); 
    } 
} 

Khi phong cách helper gốc được sử dụng (Http.TextBox) các UpdateModel (ăn tối) gọi việc như mong đợi và các giá trị mới sẽ được lưu.

Khi sử dụng kiểu trợ giúp mới (MVC2) (Http.TextBoxFor), lệnh gọi UpdateModel (bữa tối) không cập nhật các giá trị. Có, các giá trị hiện tại được tải vào trang chỉnh sửa khi tải.

Có điều gì khác mà tôi cần phải thêm vào mã bộ điều khiển để nó hoạt động không? Trình trợ giúp mới hoạt động tốt nếu tôi chỉ sử dụng một mô hình chứ không phải một mẫu ViewModel.

Cảm ơn bạn.

+0

Xin chào, tôi có cùng một vấn đề về tạo hành động. Bạn có thể vui lòng xem http://stackoverflow.com/questions/2494940/custom-viewmodel-with-mvc-2-strongly-typed-html-helpers-return-null-object-on-cre –

Trả lời

19

Vấn đề ở đây là biểu mẫu Chỉnh sửa của bạn đang sử dụng những người giúp việc được đánh máy mạnh mẽ chống lại loại DinnerFormViewModel, nhưng bạn đang gọi UpdateModel trên loại Bữa tối.

Khi bạn sử dụng những người giúp việc mạnh mẽ đánh vào loại, người trợ giúp tạo các trường biểu mẫu giả định đó là loại bạn đang đăng. Khi các loại không khớp, có vấn đề.

Tuy nhiên, điều này rất dễ sửa. Bạn có thể cung cấp tiền tố cho UpdateModel cho biết rằng bạn không cố chỉnh sửa toàn bộ mô hình, bạn đang cố chỉnh sửa thuộc tính của mô hình, trong trường hợp này là Bữa tối.

UpdateModel(dinner, "Dinner"); 

Cách tiếp cận khác là gọi UpdateModel trên ViewModel thực tế.

var viewModel = new DinnerFormViewModel(); 
viewModel.Dinner = repository.GetDinner(id); 
UpdateModel(viewModel); 

Tôi nghĩ cách tiếp cận đầu tiên tốt hơn nhiều.

+1

Không có gì tốt hơn là nhận được câu trả lời của bạn từ PM của một dự án. Cảm ơn bạn Phil, đã làm việc rất tốt. Tôi đã sử dụng ví dụ đầu tiên của bạn, đó là một đơn giản và thẳng về phía trước như tôi hy vọng. – Brettski

+0

Tôi đang làm theo cùng một ví dụ nhưng ngoại trừ việc cập nhật mô hình: http://stackoverflow.com/questions/2377065/how-to-update-using-mvc2-rc2 – Picflight

+0

Xin chào Phil, tôi có cùng một vấn đề với Tạo hành động . Tôi đang sử dụng mô hình chế độ xem tùy chỉnh cho biểu mẫu tạo. Khi tôi cố gắng tạo một đối tượng nó không bị ràng buộc từ biểu mẫu. Vì vậy, tôi đã xem xét nguồn và thấy rằng "Category.Title" thay vì "Title". Làm thế nào tôi có thể sửa chữa nó. Cảm ơn bạn –

1

Tôi không chắc chắn 100%, nhưng có vẻ như trình trợ giúp được nhập mạnh mẽ tạo id/tên "Dinner.Title" thay vì chỉ "Tiêu đề" và do đó - UpdateModel không thể ràng buộc nó.

Thật không may - tôi chưa sử dụng phương thức UpdateModel vì vậy tôi không biết giải pháp.

Bạn có thể thêm html được hiển thị cho cả hai cách tiếp cận không?


Chơi xung quanh với bộ phản xạ ATM.

Đây là những gì tôi tìm thấy:

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel: class 
{ 
    if (model == null) 
    { 
     throw new ArgumentNullException("model"); 
    } 
    if (valueProvider == null) 
    { 
     throw new ArgumentNullException("valueProvider"); 
    } 
    Predicate<string> predicate = delegate (string propertyName) { 
     return BindAttribute.IsPropertyAllowed(propertyName, base.includeProperties, base.excludeProperties); 
    }; 
    IModelBinder binder = this.Binders.GetBinder(typeof(TModel)); 
    ModelBindingContext context2 = new ModelBindingContext(); 
    context2.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(delegate { 
     return base.model; 
    }, typeof(TModel)); 
    context2.ModelName = prefix; 
    context2.ModelState = this.ModelState; 
    context2.PropertyFilter = predicate; 
    context2.ValueProvider = valueProvider; 
    ModelBindingContext bindingContext = context2; 
    binder.BindModel(base.ControllerContext, bindingContext); 
    return this.ModelState.IsValid; 
} 

thông số
- Mô hình ví dụ mô hình để cập nhật.
- tiền tố Tiền tố sử dụng khi tra cứu giá trị trong nhà cung cấp giá trị.


Vì vậy - bạn có thể thử sử dụng UpdateModel<T>(T model, string prefix) quá tải và vượt qua "Dinner" hoặc "Ăn tối." làm đối số tiền tố.

+0

Cảm ơn bạn, điều đó dường như làm điều đó. Vấn đề tôi gặp phải là tại sao thêm những người trợ giúp được đánh máy mạnh mẽ vào giàn giáo nếu bạn cần phải nhảy qua một vòng để sử dụng chúng. Tôi phải mất một cái gì đó ở đây. – Brettski

+0

@Brettski Tôi cũng gặp một số khó khăn với họ (http://stackoverflow.com/questions/2093216/asp-net-mvc2-strongly-typed-htmlhelper-indexes). Bạn không thiếu gì cả - chúng chỉ không đủ trưởng thành, thế thôi. Ít nhất - đó là cách tôi nhìn thấy nó. –

0

Một cách đơn giản hơn là sử dụng các tiền tố như tên tham số, chỉ cần làm như thế này:

public ActionResult Edit(Dinner Dinner, int DinnerID) 
{ 
    ... 
} 
1

Có lẽ một cách đơn giản hơn để đặt này là như sau. Nếu bạn đang cắt và dán mã từ bản tải xuống wrox cho hướng dẫn NerDDinner, bạn sẽ thấy có một số lỗi. Sử dụng gợi ý từ bên trên, tôi đã sửa đổi ví dụ từ 1-53.txt để làm việc này. Sự thay đổi sau:

// 
    // POST: /Dinners/Edit/2 
    [HttpPost] 
    public ActionResult Edit(int id, FormCollection formValues) 
    { 
    // Retrieve existing dinner 
    Dinner dinner = dinnerRepository.GetDinner(id); 
    DinnerFormViewModel viewModel = new DinnerFormViewModel(dinner); 

    if (TryUpdateModel(viewModel)) 
    { 
    // Persist changes back to database 
    dinnerRepository.Save(); 
    // Perform HTTP redirect to details page for the saved Dinner 
    return RedirectToAction("Details", new { id = dinner.DinnerID }); 
    } 
    else 
    { 
    return View(viewModel); 
    } 
    } 
2

Ở Trang 90 trong cuốn sách "Wrox Professional ASP.NET MVC 2" mã được liệt kê như:

if (TryUpdateModel(dinner)) { 
    dinnerRepository.Save(); 

    redirectToAction("Details", new { id=dinner.DinnerID }); 

Nhưng nó nên đọc:

if (TryUpdateModel(dinner, "Dinner")) { 
    dinnerRepository.Save(); 

    redirectToAction("Details", new { id=dinner.DinnerID }); 

Quá tải phương thức này sẽ cố gắng cập nhật mô hình được chỉ định [Bữa tối], thay vì [Dạng xem biểu tượng] mặc định, sử dụng giá trị fr om nhà cung cấp giá trị của bộ điều khiển. Về cơ bản tất cả những gì nó làm là thêm tiền tố vào tất cả các giá trị của bạn khi tìm kiếm chúng trong nhà cung cấp.

Vì vậy, khi Mô hình đang tìm cách cập nhật thuộc tính Tiêu đề của nó, nó sẽ tìm kiếm Dinner.Title, thay vì chỉ Tiêu đề trong nhà cung cấp giá trị của bộ điều khiển.

Trong khi gỡ lỗi, hãy xem phương thức Edit ActionResult và kiểm tra tham số đầu vào FormCollection. Khi bạn tìm hiểu về mảng nhập, bạn sẽ thấy các Khóa bắt đầu bằng tiền tố của đối tượng thuộc tính mà bạn đã tham chiếu trong Chế độ xem, trong trường hợp của bạn là Chế độ xem Chỉnh sửa, như sau:

<%: Html.TextBoxFor(model => model.Dinner.Title, new {size=50, @class="prettyForm" })%> 
Các vấn đề liên quan