添加一个新的 Percentage 类型和一个 PercentageConverter TypeConverter 为我解决了这个问题。
我已经声明了一个读取双 ProfitMarkup 属性的新属性,如下所示:
[Display(Name = "Markup For Profit")]
[Required]
[NotMapped]
public Percentage ProfitMarkupPercentage { get { return new Percentage(ProfitMarkup); } set { ProfitMarkup = value; } }
ProfitMarkup 以双精度形式写入/从数据库写入,ProfitMarkupPercentage 显示在剃刀页面上,如下所示:
<input asp-for="ProfitMarkupPercentage" class="form-control" autocomplete="off" />
百分比对象的代码和它的 TypeConverter 是(这是由该线程中的响应提供的:How to convert percentage string to double?):
[TypeConverter(typeof(PercentageConverter))]
public struct Percentage
{
public double Value;
public Percentage(double value)
{
Value = value;
}
static public implicit operator double(Percentage pct)
{
return pct.Value;
}
static public implicit operator string(Percentage pct) { return pct.ToString(); }
public Percentage(string value)
{
Value = 0.0;
var pct = (Percentage)TypeDescriptor.GetConverter(GetType()).ConvertFromString(value);
Value = pct.Value;
}
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
}
public string ToString(CultureInfo Culture)
{
return TypeDescriptor.GetConverter(GetType()).ConvertToString(null, Culture, this);
}
}
public class PercentageConverter : TypeConverter
{
static TypeConverter conv = TypeDescriptor.GetConverter(typeof(double));
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return conv.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(Percentage))
{
return true;
}
return conv.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
return new Percentage();
}
if (value is string)
{
string s = value as string;
s = s.TrimEnd(' ', '\t', '\r', '\n');
var percentage = s.EndsWith(culture.NumberFormat.PercentSymbol);
if (percentage)
{
s = s.Substring(0, s.Length - culture.NumberFormat.PercentSymbol.Length);
}
double result = (double)conv.ConvertFromString(s);
if (percentage)
{
result /= 100;
}
return new Percentage(result);
}
return new Percentage((double)conv.ConvertFrom(context, culture, value));
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (!(value is Percentage))
{
throw new ArgumentNullException("value");
}
var pct = (Percentage)value;
if (destinationType == typeof(string))
{
return conv.ConvertTo(context, culture, pct.Value * 100, destinationType) + culture.NumberFormat.PercentSymbol;
}
return conv.ConvertTo(context, culture, pct.Value, destinationType);
}
}
默认模型绑定器现在可以正确地填充到剃须刀页面的属性和从属性填充到剃须刀页面。
您还可以使用 Regex 向 ProfitMarkupPercentage 属性添加验证数据注释:
[RegularExpression(@"^(0*100{1,1}\.?((?<=\.)0*)?%?$)|(^0*\d{0,2}\.?((?<=\.)\d*)?%?)$", ErrorMessage = "Invalid percentage")]