asp.net MVC образцовая привязка за 1,0 и 2,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;
    }
}
5
задан David 16 March 2010 в 10:36
поделиться

1 ответ

Вы можете попробовать что-нибудь из следующих строк:

// 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 , поскольку вы больше не сможете украсить список 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)

7
ответ дан 14 December 2019 в 08:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: