2009-12-16 13 views
9

Ich habe eine Reihe von Formularen, in denen Währungswerte eingegeben werden und ich möchte, dass sie "$ 1,234.56" eingeben können. Standardmäßig werden die Modellbinder das nicht in eine Dezimalzahl parsen.So filtern Sie Formulardaten mit benutzerdefinierten Modellbinder

Was ich vorhabe, ist die Erstellung eines benutzerdefinierten Modellbinders, der DefaultModelBinder erbt, die BindProperty-Methode überschreibt, prüft, ob der Eigenschaftsdeskriptortyp dezimal ist, und wenn dies der Fall ist, streichen Sie einfach die $ und die Werte aus.

Ist dies der beste Ansatz?

Code:

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); 
} 
} 

aktualisieren

Dies ist, was ich tun endete:

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); 
    } 
} 
+1

in diesem Beitrag von Haacked einen Blick: http://haacked.com/archive/2011/03/ 19/Fixing-Bindung-zu-Dezimalen.aspx – VinnyG

Antwort

5

Es ist vernünftig es in dem Bindemittel zu tun. Ich denke jedoch, dass Decimal.Parse mit dem Währungsformat Provider oder Nummer Stil (see the docs) wäre zuverlässiger als Strippen die "$" und base aufrufen. Für den Anfang würde es nicht-US-Währung behandeln, die ein Problem für Sie eines Tages sein könnte.

+1

Wow. Ich wusste nicht, dass Decimal.Parse eine Formatierung hat, die das standardmäßig akzeptiert. Sie würden denken, dass die Modellbinder einen Weg finden würden, dies standardmäßig zu akzeptieren. Tatsächlich haben sie in diesem Beispiel http://www.asp.net/%28S%28ywiyuluxr3qb2dfva1z5lgeg%29%29/learn/mvc/tutorial-39-cs.aspx sogar einen Dezimaltyp mit einem Regex-Validator, der ein $ sagt ist ok ... Wenn ich einen Dezimaltyp habe, kommt ein Wert von $ 1,234 oder $ 1234 als 0 durch, und der Modellzustand ist nicht gültig. –

+0

Ich schaute durch die MVC-Quelle und die DataAnnotationsModelBinder-Quelle, und ich denke, es wäre am besten, Base zu nennen. Es gibt eine Menge Dinge, einschließlich der Handhabung der Fehler und des Modellstatus. Ich denke, dass ich das gemacht habe, was ich vorher gemacht habe, aber die dezimale.Parse-Funktion wird stattdessen gut funktionieren. –

1

Sie können Ihr eigenes ValidationAttribute erstellen, das überprüft, ob der Wert das richtige Format hat. Dann könnten Sie schauen, ob die Eigenschaft mit diesem Attribut dekoriert ist und es richtig binden. Attribut muss nicht ValidationAttibute sein, aber es scheint eine gute Idee zu sein.

5

In MVC3 können Sie einfach einen benutzerdefinierten Modelbinder registrieren, der die IModelBinder-Schnittstelle speziell für Dezimaltypen implementiert, und dann mit der ModelMetaData.DataTypeName -Eigenschaft für bindingContext die Verarbeitung von Währung oder Dezimalwert anweisen.

ich die Probe durch Phil Haack in his article bereitgestellt geändert habe zu zeigen, wie es getan werden könnte:

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; 
     } 
    } 
Verwandte Themen