Как отфильтровать данные формы с помощью пользовательского связывателя модели - PullRequest
9 голосов
/ 16 декабря 2009

У меня есть куча форм, в которые вводятся значения валют, и я хочу, чтобы они могли вводить «1 234,56 $». По умолчанию связующие модели не будут анализировать это в десятичное число.

То, о чем я думаю, - это создание пользовательского связывателя модели, наследующего DefaultModelBinder, переопределение метода BindProperty, проверка, является ли тип дескриптора свойства десятичным, и если это так, просто извлеките $ и из значений.

Это лучший подход?

Код:

public class CustomModelBinder : DefaultModelBinder
{
 protected override void BindProperty( ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
 {
  if( propertyDescriptor.PropertyType == typeof( decimal ) || propertyDescriptor.PropertyType == typeof( decimal? ) )
  {
   var newValue = Regex.Replace( bindingContext.ValueProvider[propertyDescriptor.Name].AttemptedValue, @"[$,]", "", RegexOptions.Compiled );
   bindingContext.ValueProvider[propertyDescriptor.Name] = new ValueProviderResult( newValue, newValue, bindingContext.ValueProvider[propertyDescriptor.Name].Culture );
  }

  base.BindProperty( controllerContext, bindingContext, propertyDescriptor );
 }
}

Обновление

Вот что я в итоге сделал:

public class CustomModelBinder : DataAnnotationsModelBinder
{
    protected override void BindProperty( ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
    {
        if( propertyDescriptor.PropertyType == typeof( decimal ) || propertyDescriptor.PropertyType == typeof( decimal? ) )
        {
            decimal newValue;
            decimal.TryParse( bindingContext.ValueProvider[propertyDescriptor.Name].AttemptedValue, NumberStyles.Currency, null, out newValue );
            bindingContext.ValueProvider[propertyDescriptor.Name] = new ValueProviderResult( newValue, newValue.ToString(), bindingContext.ValueProvider[propertyDescriptor.Name].Culture );
        }
        base.BindProperty( controllerContext, bindingContext, propertyDescriptor );
    }
}

Ответы [ 3 ]

5 голосов
/ 12 августа 2011

В MVC3 вы можете просто зарегистрировать пользовательское связующее для моделей, которое реализует интерфейс IModelBinder специально для десятичных типов, а затем указать ему обрабатывать валюту или десятичное число, используя свойство ModelMetaData.DataTypeName в bindingContext.

Я изменил образец, предоставленный Филом Хааком в его статье , чтобы продемонстрировать, как это можно сделать:

    public class DecimalModelBinder : IModelBinder
    {

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            var modelState = new ModelState { Value = valueResult };

            decimal actualValue = 0;
            try
            {

                if(bindingContext.ModelMetadata.DataTypeName == DataType.Currency.ToString())
                    decimal.TryParse(valueResult.AttemptedValue, NumberStyles.Currency, null, out actualValue);
                else
                    actualValue = Convert.ToDecimal(valueResult.AttemptedValue,CultureInfo.CurrentCulture);


            }
            catch (FormatException e)
            {
                modelState.Errors.Add(e);
            }

            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
            return actualValue;
        }
    }
5 голосов
/ 16 декабря 2009

Разумно сделать это в переплете. Однако я думаю, что Decimal.Parse с поставщиком формата валюты или стилем чисел ( см. Документы ) будет более надежным, чем удаление "$" и вызов base. Для начала, он будет обрабатывать неамериканскую валюту, что может стать проблемой для вас когда-нибудь.

1 голос
/ 16 декабря 2009

Вы можете создать собственный атрибут ValidationAttribute, который проверяет, имеет ли значение правильный формат. Тогда вы могли бы посмотреть, украшено ли свойство этим атрибутом, и правильно связать его. Атрибут не обязательно должен быть ValidationAttibute, но кажется хорошей идеей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...