My application has many models, many of which contain percentage data. These are represented as decimal
or decimal?
structs in the model. However, not all properties with decimal
structs are percentages. Some should be treated like regular decimals.
The percentages need special attention:
{0:P2}
format. (I have this part working.)I started down the road of creating a PercentModelBinder
that implements IModelBinder
, but then realized that you can only apply the ModelBinderAttribute
to a class, not a property.
What's the best way to handle this case where some (but not all) uses of a type need special handling both for display and binding?
Every solution I think of smells badly of overkill, fighting the MVC framework. Surely there is a better way than:
Percentage
struct and using it as the basis for the IModelBinder and EditorTemplates, or decimal
and decimal?
and changing the parsing logic based on intimate knowledge of my model, orOne possibility is to write a custom metadata aware attribute:
public class PercentageAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["percentage"] = metadata.EditFormatString;
}
}
then decorate your view model properties that represent percentages with it:
public class MyViewModel
{
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:P2}")]
[Percentage]
public decimal? Percentage { get; set; }
}
and inside the custom model binder test for the presence of this value:
public class PercentageModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelMetadata.AdditionalValues.ContainsKey("percentage"))
{
var format = (string)bindingContext.ModelMetadata.AdditionalValues["percentage"];
// TODO: do the custom parsing here
throw new NotImplementedException();
}
else
{
// Let the default parsing occur
return base.BindModel(controllerContext, bindingContext);
}
}
}
Now you can register this model binder to all decimals.
Instead of representing your percentage properties using decimal primitives (see Primitive Obsession), why don't you create a Percentage type to wrap your desired functionality? You should have much more flexibility doing it that way...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With