Percentage properties in MVC 3

巧了我就是萌 提交于 2019-12-03 17:35:24

问题


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:

  • For display, they should use {0:P2} format. (I have this part working.)
  • For editing, they should allow the same format as the display, i.e. "95" or "95%" or "95.00 %" all bind to a value of 0.95.

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:

  • Creating a custom Percentage struct and using it as the basis for the IModelBinder and EditorTemplates, or
  • Reimplementing the default binding behavior of decimal and decimal? and changing the parsing logic based on intimate knowledge of my model, or
  • Implementing a custom model binder for each class that contains a percentage property, or
  • Using fake proxy properties in the model (i.e. breaking MVC)

回答1:


One 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.




回答2:


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...




回答3:


Bind to a string in your view model. Then when do the conversion back to the real model.



来源:https://stackoverflow.com/questions/7234966/percentage-properties-in-mvc-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!