我同意jrummell以上的解決方案: 當您使用EditorFor
-extension,你必須編寫自定義 編輯模板來描述可視化組件。
在某些情況下,我認爲使用具有相同數據類型的 幾個模型屬性的編輯器模板有點僵硬。在我的情況下,我想在我的模型中使用應顯示爲格式化字符串的十進制貨幣值。我想在我的視圖中使用相應的CSS類來設置這些屬性的樣式。
我已經看到其他的實現,其中的HTML參數已被附加到使用模型中的註釋屬性。這在我看來是不好的,因爲像CSS定義這樣的視圖信息應該在視圖中而不是在數據模型中設置。
所以我工作的另一種解決方案:
我的模型包含decimal?
屬性,我想作爲一個貨幣領域使用。 問題是,我想在模型中使用數據類型decimal?
,但在視圖中使用格式掩碼(例如「42,13€」)將格式化字符串中的十進制值顯示爲 。
這裏是我的模型定義:
[DataType(DataType.Currency), DisplayFormat(DataFormatString = "{0:C2}", ApplyFormatInEditMode = true)]
public decimal? Price { get; set; }
格式掩碼0:C2
格式化decimal
有2位小數。 ApplyFormatInEditMode
很重要, 如果您要使用此屬性填充視圖中的可編輯文本字段。所以我把它設置爲true
,因爲在我的情況下我想把它放到一個文本框中。
通常你必須在這樣的視圖使用EditorFor
-extension:
<%: Html.EditorFor(x => x.Price) %>
問題:
我不能在這裏添加CSS類,因爲我可以用Html.TextBoxFor
例如做。
要提供自己的CSS類(或其他HTML屬性,如tabindex
,或readonly
)與EditorFor
-extension是寫一個自定義的HTML-助手, 像Html.CurrencyEditorFor
。下面是執行:
public static MvcHtmlString CurrencyEditorFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Object htmlAttributes)
{
TagBuilder tb = new TagBuilder("input");
// We invoke the original EditorFor-Helper
MvcHtmlString baseHtml = EditorExtensions.EditorFor<TModel, TValue>(html, expression);
// Parse the HTML base string, to refurbish the CSS classes
string basestring = baseHtml.ToHtmlString();
HtmlDocument document = new HtmlDocument();
document.LoadHtml(basestring);
HtmlAttributeCollection originalAttributes = document.DocumentNode.FirstChild.Attributes;
foreach(HtmlAttribute attr in originalAttributes) {
if(attr.Name != "class") {
tb.MergeAttribute(attr.Name, attr.Value);
}
}
// Add the HTML attributes and CSS class from the View
IDictionary<string, object> additionalAttributes = (IDictionary<string, object>) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
foreach(KeyValuePair<string, object> attribute in additionalAttributes) {
if(attribute.Key == "class") {
tb.AddCssClass(attribute.Value.ToString());
} else {
tb.MergeAttribute(attribute.Key, attribute.Value.ToString());
}
}
return MvcHtmlString.Create(HttpUtility.HtmlDecode(tb.ToString(TagRenderMode.SelfClosing)));
}
的想法是使用原始EditorFor
-extension產生的HTML代碼,並解析這個HTML輸出字符串用我們自己的CSS類來代替創建 CSS的HTML屬性和追加其他額外的HTML屬性。對於HTML解析,我使用HtmlAgilityPack(使用谷歌)。
在視圖中,您可以使用這個助手是這樣的(不要忘記把相應的命名空間到你的視圖目錄web.config
!):
<%: Html.CurrencyEditorFor(x => x.Price, new { @class = "mypricestyles", @readonly = "readonly", @tabindex = "-1" }) %>
使用這個幫手,您的貨幣價值應在視圖中顯示得很好。
如果你想發佈你的視圖(表單),那麼通常所有的模型屬性將被髮送到你的控制器的操作方法。 在我們的例子中,將會提交一個字符串格式的十進制值,這個值將由ASP.NET MVC內部模型綁定類來處理。
由於此模型聯編程序期望decimal?
值,但獲取字符串格式化的值,將引發異常。所以我們必須 將格式化的字符串轉換回decimal?
- 表示。因此自己的ModelBinder
- 實施是必要的,其中 將貨幣十進制值轉換回默認的十進制值(「42,13€」=>「42.13」)。
這裏就是這樣一個模型綁定的實現:
public class DecimalModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
object o = null;
decimal value;
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var modelState = new ModelState { Value = valueResult };
try {
if(bindingContext.ModelMetadata.DataTypeName == DataType.Currency.ToString()) {
if(decimal.TryParse(valueResult.AttemptedValue, NumberStyles.Currency, null, out value)) {
o = value;
}
} else {
o = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
}
} catch(FormatException e) {
modelState.Errors.Add(e);
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return o;
}
}
粘合劑已在global.asax
文件應用程序的登記:
protected void Application_Start()
{
...
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
...
}
也許解決方案將幫助別人。
+1,我還想提一提:關於這個問題的Brad Wilson博客系列http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction .html – smartcaveman
@smartcaveman感謝您的鏈接,我不記得是誰寫的那個系列。出於某種原因,我認爲這是scottgu! – jrummell
感謝您的回答,它的工作! – kbaccouche