2011-01-18 16 views
6

Znaleźliśmy dziwne zachowanie w DropDownListFor (wydanie ASP.NET MVC3). W menu rozwijanym wybiera wartość właściwości ViewBag zamiast wartości właściwości Model.Wartość właściwości ViewBag w DropDownListFor zamiast wartości właściwości Model

Model:

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

Index Controller działanie:

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

Widok:

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

To pokaże pole tekstowe z "Rosja" wartości i rozwijanym z "Danmark" wartości wybrane zamiast "Rosja".

Nie znalazłem żadnej dokumentacji dotyczącej tego zachowania. Czy to zachowanie jest normalne? I dlaczego jest to normalne? Ponieważ bardzo trudno kontrolować nazwy właściwości ViewBag i Model.

This sample MVC3 project sources

Odpowiedz

5

Nie jestem pewien, dlaczego ta decyzja została podjęta, ale stało się tak, ponieważ platforma MVC próbowała użyć wartości podanej w ViewData przed użyciem wartości dostarczonej przez parametr. Dlatego ViewBag.Country przesłania wartość dostarczoną przez parametr Model.Country.

To było jak było written w ramach MVC w metodzie SelectInternalprywatny.

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

Ten kod defaultValue = htmlHelper.ViewData.Eval(fullName); próbował uzyskać wartość od ViewData i czy może on uzyskać wartość, zastąpi on dostarczony parametr selectList z nowej listy.

Mam nadzieję, że to pomoże. Dzięki.

węzeł boczny: ViewBag jest po prostu dynamiczną klasą otoków ViewData.

4

Poniższy wiersz ze swojego sposobu działania jest to, co jest mylące kod:

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

To dlatego, że pomocnicy html zajrzeć do kilku różnych miejsc, aby podnieść wartości generowanych kontroli. W takim przypadku ViewData["Country"] ściera się z ModelState["Country"] Zmień nazwę tej właściwości na coś innego i wszystko powinno działać.

+0

Czy sugerujesz, aby zawsze używać prefiksu dla nazwy właściwości ViewBag, aby uniknąć konfliktu nazw? Dawny. ViewBag.ViewBag_Country –

+0

Święte bzdury, masz rację. Dziękuję za to ... uratowałem mój dzień ... :) – dizzwave

Powiązane problemy