2016-05-13 81 views
0

我正在試驗自定義ModelMetadataProvider。看起來像TextBoxFor這樣的一些html助手使用這些就好了。但是,在其他情況下,像DropDownListFor,他們贊成ViewData。例如,看看我看到的一些反射代碼:元數據vs HtmlHelper中的ViewData

bool flag = false; 
    if (selectList == null) 
    { 
    selectList = SelectExtensions.GetSelectData(htmlHelper, name); 
    flag = true; 
    } 
    object defaultValue = allowMultiple ? htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof (string[])) : htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof (string)); 
    if (defaultValue == null && !string.IsNullOrEmpty(name)) 
    { 
    if (!flag) 
     defaultValue = htmlHelper.ViewData.Eval(name); 
    else if (metadata != null) 
     defaultValue = metadata.Model; 
    } 

請注意所有嘗試獲取「defaultValue」的所有嘗試。使用metadata.Model是最後一個。爲什麼在這裏分離?如果您通過代碼追蹤代碼,最終您最終會對ViewData.Eval進行調用,而後者只是使用反射來將值從模型中取出。有沒有像自定義的ViewData提供者那樣的東西來彌補這個差距?

編輯:我開始傾向於這是一個在框架中的錯誤的想法。

考慮兩段代碼:

@Html.DropDownListFor(model => model.ErrorData.Shift, Model.ShiftOptions, new { @class = "form-control" }) 

上述代碼通過在選項 「Model.ShiftOptions」。正因爲如此,它沒有通過條件「selectList == null」,因此從不設置「標誌」,而是繼續嘗試僅通過反射(Eval調用)從類型獲取默認值。

然而與此代碼:

@{ ViewData[Html.NameFor(m => m.ErrorData.Shift).ToString()] = Model.ShiftOptions;} 
@Html.DropDownListFor(model => model.ErrorData.Shift,null, new { @class = "form-control" }) 

...「標誌」是現在滿意了,默認值現在檢索metadata.Model。爲什麼提供列表選項的不同機制會改變(或者甚至影響這個問題)從默認值檢索的地方?

回答

1

所有HtmlHelper方法用於生成表單控件第一檢查是否有在ModelState(該GetModelStateValue()方法),用於該屬性的值來處理,其中的形式已被提交以無效值,並返回視圖的情況下(參照this answer的第二部分,解釋爲什麼這是默認行爲)。

在使用DropDownList()的情況下,例如

@Html.DropDownList("xxx", null, "--Please select--") 

其中xxx是已被添加作爲ViewBag屬性IEnumerable<SelectListItem>,的selectList值爲null並執行在第一if塊中的代碼並且flag的值是true(並且還注意該模型可能具有或不具有名稱爲xxx的屬性,這意味着metadata可能是null

替代地,如果使用強類型DropDownListFor()方法,例如

@Html.DropDownListFor(m => m.SomeProperty, Model.SomePropertyList, "--Please select--") 

selectList值不是null(假設SomePropertyListIEnumerable<SelectListItem>並且不是null)和flag值爲false

因此,各種檢查只是考慮到您可以使用DropDownList()DropDownListFor()生成<select> el ement,以及您是否綁定到模型屬性。

邊注:實際的代碼(從private static MvcHtmlString SelectInternal()法)bool usedViewData = false;,不bool flag = false;

+0

感謝偉大的答案。但是,我不確定GetModelStateValue在做什麼,或者創建了底層字典的時候,但它似乎並不反映元數據中的內容。在我的元數據提供者的CreateMetadata方法中,我可以設置返回的ModelMetadata.Model屬性==「test」。然後當調用「TextBoxFor」時,文本框全部填充「test」。這不符合DropDownListFor出於某種原因,它繼續調用ViewData.Eval,它本質上只是試圖獲得純粹基於類型的屬性的默認值。 –

+0

你讀過我鏈接到的答案嗎?總是先調用'GetModelStateValue()'來獲取'ModelState'的值(例如,如果您將模型發佈回控制器方法,則提交的值將添加到'ModelState'中,然後如果返回視圖, 'ModelState'之前檢查其他) –

+0

不,我applogize,直到現在我沒有注意到鏈接。但我不確定它是否相關。在從模型狀態檢索失敗(我猜我可以強制使用ModelState.Clear)之後,它繼續並調用ViewData.Eval(這可以歸結爲對類型的反射調用)INSTEAD從元數據獲取值?爲什麼DropDownList在其他幫助者青睞元數據時喜歡這種類型? –