Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I agree to the solution of jrummell above: When you use the <code>EditorFor</code>-Extension, you have to write a custom editor template to describe the visual components.</p> <p>In some cases, I think it is a bit stiff to use an editor template for several model properties with the same datatype. In my case, I want to use decimal currency values in my model which should be displayed as a formatted string. I want to style these properties using corresponding CSS classes in my views. </p> <p>I have seen other implementations, where the HTML-Parameters have been appended to the properties using annotations in the Model. This is bad in my opinion, because view information, like CSS definitions should be set in the view and not in a data model.</p> <p>Therefore I'm working on another solution:</p> <p>My model contains a <code>decimal?</code> property, which I want to use as a currency field. The Problem is, that I want to use the datatype <code>decimal?</code> in the model, but display the decimal value in the view as formatted string using a format mask (e.g. "42,13 €").</p> <p>Here is my model definition:</p> <pre><code>[DataType(DataType.Currency), DisplayFormat(DataFormatString = "{0:C2}", ApplyFormatInEditMode = true)] public decimal? Price { get; set; } </code></pre> <p>Format mask <code>0:C2</code> formats the <code>decimal</code> with 2 decimal places. The <code>ApplyFormatInEditMode</code> is important, if you want to use this property to fill a editable textfield in the view. So I set it to <code>true</code>, because in my case I want to put it into a textfield.</p> <p>Normally you have to use the <code>EditorFor</code>-Extension in the view like this:</p> <pre><code>&lt;%: Html.EditorFor(x =&gt; x.Price) %&gt; </code></pre> <p>The Problem: </p> <p>I cannot append CSS classes here, as I can do it using <code>Html.TextBoxFor</code> for example.</p> <p>To provide own CSS classes (or other HTML attributes, like <code>tabindex</code>, or <code>readonly</code>) with the <code>EditorFor</code>-Extension is to write an custom HTML-Helper, like <code>Html.CurrencyEditorFor</code>. Here is the implementation:</p> <pre><code>public static MvcHtmlString CurrencyEditorFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html, Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression, Object htmlAttributes) { TagBuilder tb = new TagBuilder("input"); // We invoke the original EditorFor-Helper MvcHtmlString baseHtml = EditorExtensions.EditorFor&lt;TModel, TValue&gt;(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&lt;string, object&gt; additionalAttributes = (IDictionary&lt;string, object&gt;) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach(KeyValuePair&lt;string, object&gt; 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))); } </code></pre> <p>The idea is to use the original <code>EditorFor</code>-Extension to produce the HTML-Code and to parse this HTML output string to replace the created CSS Html-Attribute with our own CSS classes and append other additional HTML attributes. For the HTML parsing, I use the HtmlAgilityPack (use google).</p> <p>In the View you can use this helper like this (don't forget to put the corresponding namespace into the <code>web.config</code> in your view-directory!):</p> <pre><code>&lt;%: Html.CurrencyEditorFor(x =&gt; x.Price, new { @class = "mypricestyles", @readonly = "readonly", @tabindex = "-1" }) %&gt; </code></pre> <p>Using this helper, your currency value should be displayed well in the view. </p> <p>If you want to post your view (form), then normally all model properties will be sent to your controller's action method. In our case a string formatted decimal value will be submitted, which will be processed by the ASP.NET MVC internal model binding class.</p> <p>Because this model binder expects a <code>decimal?</code>-value, but gets a string formatted value, an exception will be thrown. So we have to convert the formatted string back to it's <code>decimal?</code> - representation. Therefore an own <code>ModelBinder</code>-Implementation is necessary, which converts currency decimal values back to default decimal values ("42,13 €" => "42.13").</p> <p>Here is an implementation of such a model binder:</p> <pre><code>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; } } </code></pre> <p>The binder has to be registered in the <code>global.asax</code> file of your application:</p> <pre><code>protected void Application_Start() { ... ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder()); ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder()); ... } </code></pre> <p>Maybe the solution will help someone.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload