上記の jrummell の解決策に同意します。-Extension を使用する場合EditorFor
、ビジュアル コンポーネントを記述するカスタム エディター テンプレートを作成する必要があります。
場合によっては、同じデータ型の複数のモデル プロパティに対してエディター テンプレートを使用するのは少し難しいと思います。私の場合、フォーマットされた文字列として表示されるモデルで 10 進数の通貨値を使用したいと考えています。ビューで対応する CSS クラスを使用して、これらのプロパティのスタイルを設定したいと考えています。
モデルの注釈を使用して HTML パラメータがプロパティに追加されている他の実装を見てきました。CSS定義のようなビュー情報は、データモデルではなくビューに設定する必要があるため、これは私の意見では悪いです。
したがって、私は別の解決策に取り組んでいます:
私のモデルにはdecimal?
、通貨フィールドとして使用したいプロパティが含まれています。問題は、モデルでデータ型を使用したいのですがdecimal?
、フォーマット マスクを使用してフォーマットされた文字列としてビューに 10 進値を表示することです (例: "42,13 €")。
これが私のモデル定義です:
[DataType(DataType.Currency), DisplayFormat(DataFormatString = "{0:C2}", ApplyFormatInEditMode = true)]
public decimal? Price { get; set; }
フォーマット マスクは、小数点以下 2 桁で0:C2
フォーマットします。decimal
このApplyFormatInEditMode
プロパティを使用してビューの編集可能なテキスト フィールドに入力する場合、これは重要です。true
私の場合はテキストフィールドに入れたいので、に設定しました。
通常、次EditorFor
のようにビューで -Extensionを使用する必要があります。
<%: Html.EditorFor(x => x.Price) %>
問題:
Html.TextBoxFor
たとえば、CSS クラスをここに追加することはできません。
-Extensionを使用して独自の CSS クラス (または や などの他の HTML 属性tabindex
)readonly
を提供するには、 のようなカスタム HTML ヘルパーを記述します。実装は次のとおりです。EditorFor
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 Html-Attribute を独自の CSS クラスに置き換え、他の HTML 属性を追加するという考え方です。HTML の解析には、HtmlAgilityPack (Google を使用) を使用します。
web.config
ビューでは、このヘルパーを次のように使用できます (対応する名前空間をビュー ディレクトリに配置することを忘れないでください!):
<%: Html.CurrencyEditorFor(x => x.Price, new { @class = "mypricestyles", @readonly = "readonly", @tabindex = "-1" }) %>
このヘルパーを使用すると、通貨の値がビューに適切に表示されるはずです。
ビュー (フォーム) を投稿する場合、通常、すべてのモデル プロパティがコントローラーのアクション メソッドに送信されます。この場合、文字列形式の 10 進数値が送信され、ASP.NET MVC 内部モデル バインディング クラスによって処理されます。
このモデル バインダーはdecimal?
-value を想定していますが、文字列形式の値を取得するため、例外がスローされます。そのため、フォーマットされた文字列を元のdecimal?
表現に変換する必要があります。したがって、ModelBinder
通貨の 10 進値をデフォルトの 10 進値に変換する独自の実装が必要です ("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());
...
}
多分解決策は誰かを助けるでしょう。