2013-01-02 38 views
0

從我的MVC3應用程序中獲取一些非常惱人的行爲。所以我有一個模型3個值:ViewBag多SelectListItems

[DisplayName("Airlines ")] 
[StringLength(2, ErrorMessage = "Airline codes can only be 2 characters in length")] 
public string AirlineCode1 { get; set; } 

[DisplayName("Airlines")] 
[StringLength(2, ErrorMessage = "Airline codes can only be 2 characters in length")] 
public string AirlineCode2 { get; set; } 

[DisplayName("Airlines")] 
[StringLength(2, ErrorMessage = "Airline codes can only be 2 characters in length")] 
public string AirlineCode3 { get; set; } 

現在,這些是從DropDowList填充,所以我在ViewBag彈出的DropDownListItem S和視圖這樣使它們:

@Html.LabelFor(l => l.AirlineCode1) <span>(select/enter code in box on right)</span> 
<div id="airportCode1"> 
    @Html.DropDownListFor(d => d.AirlineCode, ViewBag.AirLines as List<SelectListItem>) <input type="text" maxlength="2" value="@Model.AirlineCode1" /> 
</div> 
<div id="airportCode2" style="@Model.AirlineCode2Style"> 
    @Html.DropDownListFor(d => d.AirlineCode, ViewBag.AirLines2 as List<SelectListItem>) <input type="text" maxlength="2" value="@Model.AirlineCode2" /> 
</div> 
<div id="airportCode3"> 
    @Html.DropDownListFor(d => d.AirlineCode3, ViewBag.AirLines3 as List<SelectListItem>) <input type="text" maxlength="2" value="@Model.AirlineCode3" /> 
</div> 

所以我的控制器看起來像:

IEnumerable<SelectListItem> airLines = PopulateAirlines(user); 
ViewBag.AirLines = airLines; 
ViewBag.AirLines2 = airLines; 
ViewBag.AirLines3 = airLines; 

現在在某些情況下,我想prepoulate AirLineCode在模型。所以我在控制器中設置了模型值。這導致了一些奇怪的行爲。突然間,我所有的DropDownList s 都包含了預填充值!

檢查模型,值只在AirLineCode1中設置。檢查了ViewBag,沒有選擇SelectListItems。所以我認爲ViewBag必須保持一個參考。所以我將我的代碼更改爲:

ViewBag.AirLines = PopulateAirlines(user); 
ViewBag.AirLines2 = PopulateAirlines(user); 
ViewBag.AirLines3 = PopulateAirlines(user); 

繁榮,固定。問題是PopulateAirlines是一個昂貴的過程!

問題是ViewBag似乎在維護3 SelectListItemList之間的引用。如何阻止它這樣做,仍然只打一個電話給PopulateAirlines(user);

我嘗試下面的代碼,這完全炸燬了:

IEnumerable<SelectListItem> airLines = PopulateAirlines(user); 
ViewBag.AirLines = airLines; 
ViewBag.AirLines2 = airLines.Select(s => new SelectListItem() { Text = s.Text, Value = s.Value, Selected = s.Selected }); 
ViewBag.AirLines3 = airLines.Select(s => new SelectListItem() { Text = s.Text, Value = s.Value, Selected = s.Selected }); 

與錯誤:

There is no ViewData item of type 'IEnumerable' that has the key 'AirlineCode2'.

什麼?!

+0

擺脫ViewBag。它不是強類型的,也不是一種難以傳遞數據的方式。創建一個ViewModel與您的各種航空公司信息項目,解決問題:) –

+0

我從不贊同這個論點。我不希望返回這些數據,只是填充下拉列表,所以使用ViewBag會更有效,因爲它會阻止列表在兩個方向上進行序列化。對我來說,ViewBag是隻讀的創建和忘記數據。 – Liam

+1

不,這不是更高效。它的基本上可以忽略不計,僅僅因爲它在一個視圖模型中指向一個方向並不意味着它必須處於接收視圖模型中,甚至不一定是在這個問題上。另一方面,你有脆弱的實現傾向於重構錯誤,通過在html助手中使用viewbag隱藏在幕後的行爲,並且通常建議不要在除了最小的web應用程序之外的任何實踐中使用。有些人甚至說永遠不會使用它(我通常接受它用於像標題一樣的標準使用)。看到Darin Dmitrov在這裏的很多帖子,對於一些很好的參考 –

回答

1

這可能是因爲在此代碼:

IEnumerable<SelectListItem> airLines = PopulateAirlines(user); 
ViewBag.AirLines = airLines; 
ViewBag.AirLines2 = airLines; 
ViewBag.AirLines3 = airLines; 

所有ViewBag屬性是指相同的列表。因此,當引用任何屬性時,對列表的更改都會反映出來。當您調用PopulateAirlines()方法時,您正在創建3個不同的列表。

你需要做三個不同的列表,但只有使用PopulateAirlines方法,然後克隆兩次創建的第一個。這不會太昂貴。