asp.net MVC 1.0和2.0货币模型绑定

发布于 2024-08-25 03:20:29 字数 1712 浏览 5 评论 0原文

我想创建模型绑定功能,以便用户可以输入“,”“。”等等,用于绑定到我的 ViewModel 的双精度值的货币值。

我能够在 MVC 1.0 中通过创建自定义模型绑定器来执行此操作,但是自从升级到 MVC 2.0 后,此功能不再起作用。

有谁有任何想法或更好的解决方案来执行此功能?更好的解决方案是使用一些数据注释或自定义属性。

public class MyViewModel
{
    public double MyCurrencyValue { get; set; }
}

首选解决方案是这样的...

public class MyViewModel
{
    [CurrencyAttribute]
    public double MyCurrencyValue { get; set; }
}

下面是我在 MVC 1.0 中进行模型绑定的解决方案。

public class MyCustomModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        object result = null;

        ValueProviderResult valueResult;
        bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName, out valueResult);
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueResult);

        if (bindingContext.ModelType == typeof(double))
        {
            string modelName = bindingContext.ModelName;
            string attemptedValue = bindingContext.ValueProvider[modelName].AttemptedValue;

            string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
            string alternateSeperator = (wantedSeperator == "," ? "." : ",");

            try
            {
                result = double.Parse(attemptedValue, NumberStyles.Any);
            }
            catch (FormatException e)
            {
                bindingContext.ModelState.AddModelError(modelName, e);
            }
        }
        else
        {
            result = base.BindModel(controllerContext, bindingContext);
        }

        return result;
    }
}

I would like to create model binding functionality so a user can enter ',' '.' etc for currency values which bind to a double value of my ViewModel.

I was able to do this in MVC 1.0 by creating a custom model binder, however since upgrading to MVC 2.0 this functionality no longer works.

Does anyone have any ideas or better solutions for performing this functionality? A better solution would be to use some data annotation or custom attribute.

public class MyViewModel
{
    public double MyCurrencyValue { get; set; }
}

A preferred solution would be something like this...

public class MyViewModel
{
    [CurrencyAttribute]
    public double MyCurrencyValue { get; set; }
}

Below is my solution for model binding in MVC 1.0.

public class MyCustomModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        object result = null;

        ValueProviderResult valueResult;
        bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName, out valueResult);
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueResult);

        if (bindingContext.ModelType == typeof(double))
        {
            string modelName = bindingContext.ModelName;
            string attemptedValue = bindingContext.ValueProvider[modelName].AttemptedValue;

            string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
            string alternateSeperator = (wantedSeperator == "," ? "." : ",");

            try
            {
                result = double.Parse(attemptedValue, NumberStyles.Any);
            }
            catch (FormatException e)
            {
                bindingContext.ModelState.AddModelError(modelName, e);
            }
        }
        else
        {
            result = base.BindModel(controllerContext, bindingContext);
        }

        return result;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

波浪屿的海角声 2024-09-01 03:20:30

您可以尝试以下几行:

// Just a marker attribute
public class CurrencyAttribute : Attribute
{
}

public class MyViewModel
{
    [Currency]
    public double MyCurrencyValue { get; set; }
}


public class CurrencyBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext, 
        PropertyDescriptor propertyDescriptor, 
        IModelBinder propertyBinder)
    {
        var currencyAttribute = propertyDescriptor.Attributes[typeof(CurrencyAttribute)];
        // Check if the property has the marker attribute
        if (currencyAttribute != null)
        {
            // TODO: improve this to handle prefixes:
            var attemptedValue = bindingContext.ValueProvider
                .GetValue(propertyDescriptor.Name).AttemptedValue;
            return SomeMagicMethodThatParsesTheAttemptedValue(attemtedValue);
        }
        return base.GetPropertyValue(
            controllerContext, 
            bindingContext, propertyDescriptor, 
            propertyBinder
        );
    }
}

public class HomeController: Controller
{
    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(CurrencyBinder))] MyViewModel model)
    {
        return View();
    }
}

更新:

这是绑定器的改进(请参阅前面代码中的TODO部分):

if (!string.IsNullOrEmpty(bindingContext.ModelName))
{
    var attemptedValue = bindingContext.ValueProvider
        .GetValue(bindingContext.ModelName).AttemptedValue;
    return SomeMagicMethodThatParsesTheAttemptedValue(attemtedValue);
}

为了处理集合,您需要在Application_Start<中注册绑定器/code> 因为您将不再能够使用 ModelBinderAttribute 来装饰列表:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.Add(typeof(MyViewModel), new CurrencyBinder());
}

然后您的操作可能如下所示:

[HttpPost]
public ActionResult Index(IList<MyViewModel> model)
{
    return View();
}

总结重要部分:

bindingContext.ValueProvider.GetValue(bindingContext.ModelName)

此绑定器的进一步改进步骤是处理验证(AddModelError/SetModelValue)

You might try something among the lines:

// Just a marker attribute
public class CurrencyAttribute : Attribute
{
}

public class MyViewModel
{
    [Currency]
    public double MyCurrencyValue { get; set; }
}


public class CurrencyBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext, 
        PropertyDescriptor propertyDescriptor, 
        IModelBinder propertyBinder)
    {
        var currencyAttribute = propertyDescriptor.Attributes[typeof(CurrencyAttribute)];
        // Check if the property has the marker attribute
        if (currencyAttribute != null)
        {
            // TODO: improve this to handle prefixes:
            var attemptedValue = bindingContext.ValueProvider
                .GetValue(propertyDescriptor.Name).AttemptedValue;
            return SomeMagicMethodThatParsesTheAttemptedValue(attemtedValue);
        }
        return base.GetPropertyValue(
            controllerContext, 
            bindingContext, propertyDescriptor, 
            propertyBinder
        );
    }
}

public class HomeController: Controller
{
    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(CurrencyBinder))] MyViewModel model)
    {
        return View();
    }
}

UPDATE:

Here's an improvement of the binder (see TODO section in previous code):

if (!string.IsNullOrEmpty(bindingContext.ModelName))
{
    var attemptedValue = bindingContext.ValueProvider
        .GetValue(bindingContext.ModelName).AttemptedValue;
    return SomeMagicMethodThatParsesTheAttemptedValue(attemtedValue);
}

In order to handle collections you will need to register the binder in Application_Start as you will no longer be able to decorate the list with the ModelBinderAttribute:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.Add(typeof(MyViewModel), new CurrencyBinder());
}

And then your action could look like this:

[HttpPost]
public ActionResult Index(IList<MyViewModel> model)
{
    return View();
}

Summarizing the important part:

bindingContext.ValueProvider.GetValue(bindingContext.ModelName)

A further improvement step of this binder would be to handle validation (AddModelError/SetModelValue)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文