2011-01-18 54 views
6

Chúng tôi đã tìm thấy hành vi lạ trong DropDownListFor (bản phát hành MVC3 ASP.NET). Nó chọn giá trị thuộc tính ViewBag thay vì giá trị thuộc tính Model trong menu thả xuống.Giá trị thuộc tính ViewBag trong DropDownListFor thay vì giá trị thuộc tính Model

mẫu:

public class Country { 
    public string Name { get; set; } 
} 
public class User { 
    public Country Country { get; set; } 
} 

khiển Index hành động:

ViewBag.CountryList = new List<Country> { /* Dropdown collection */ 
    new Country() { Name = "Danmark" }, 
    new Country() { Name = "Russia" } }; 

var user = new User(); 
user.Country = new Country(){Name = "Russia"}; /* User value */ 
ViewBag.Country = new Country() { Name = "Danmark" }; /* It affects user */ 
return View(user); 

Xem:

@Html.EditorFor(user => user.Country.Name)  
@Html.DropDownListFor(user => user.Country.Name, 
    new SelectList(ViewBag.CountryList, "Name", "Name", Model.Country), "...") 

Nó sẽ hiển thị hộp văn bản có giá trị "Nga" và thả xuống với giá trị "Danmark" được chọn thay vì "Nga".

Tôi không tìm thấy bất kỳ tài liệu nào về hành vi này. Hành vi này có bình thường không? Và tại sao nó lại bình thường? Bởi vì rất khó kiểm soát các tên thuộc tính của ViewBag và Model.

This sample MVC3 project sources

Trả lời

5

Tôi không chắc tại sao quyết định này được đưa ra, nhưng điều đó đã xảy ra vì khung MVC đã cố gắng sử dụng giá trị do ViewData cung cấp trước khi sử dụng giá trị do tham số cung cấp. Đó là lý do tại sao ViewBag.Country ghi đè giá trị được cung cấp bởi thông số Model.Country.

Đó là cách nó được written trong khung MVC theo phương thức riêngSelectInternal.

object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); 

// If we haven't already used ViewData to get the entire list of items then we need to 
// use the ViewData-supplied value before using the parameter-supplied value. 
if (!usedViewData) { 
    if (defaultValue == null) { 
     defaultValue = htmlHelper.ViewData.Eval(fullName); 
    } 
} 

if (defaultValue != null) { 
    IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue }; 
    IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture); 
    HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase); 
    List<SelectListItem> newSelectList = new List<SelectListItem>(); 

    foreach (SelectListItem item in selectList) { 
     item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text); 
     newSelectList.Add(item); 
    } 
    selectList = newSelectList; 
} 

này đang defaultValue = htmlHelper.ViewData.Eval(fullName); cố gắng để có được giá trị từ ViewData và nếu nó có thể nhận được giá trị, nó sẽ ghi đè lên các thông số được cung cấp selectList với danh sách mới.

Hy vọng điều đó có thể hữu ích. Cảm ơn.

nút phụ: ViewBag chỉ là lớp trình bao bọc động của Chế độ xem.

4

Các dòng sau từ phương pháp hành động của bạn là gì là khó hiểu mã:

ViewBag.Country = new Country() { Name = "Danmark" }; /* It affects user */ 

Đó là bởi vì những người giúp đỡ html nhìn vào một vài nơi khác nhau để lấy giá trị cho các điều khiển được tạo ra. Trong trường hợp này, ViewData["Country"] đang xung đột với ModelState["Country"] Đổi tên thuộc tính đó thành một thứ khác và mọi thứ sẽ hoạt động.

+0

Bạn có đề xuất luôn sử dụng tiền tố cho tên thuộc tính ViewBag để tránh xung đột tên không? Ví dụ ViewBag.ViewBag_Country –

+0

holy crap, bạn nói đúng. Cảm ơn vì điều này ... đã cứu ngày của tôi ... :) – dizzwave

Các vấn đề liên quan