2010-03-16 11 views
5

Ich möchte Model Binding-Funktionalität erstellen, damit ein Benutzer geben kann "," "." usw. für Währungswerte, die an einen doppelten Wert meines ViewModels binden.asp.net MVC 1.0 und 2.0 Währungsmodell verbindlich

Ich konnte dies in MVC 1.0 durch Erstellen eines benutzerdefinierten Modellbinders tun, aber seit dem Upgrade auf MVC 2.0 funktioniert diese Funktionalität nicht mehr.

Hat jemand Ideen oder bessere Lösungen zum Ausführen dieser Funktionalität? Eine bessere Lösung wäre die Verwendung einer Datenannotation oder eines benutzerdefinierten Attributs.

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

Eine bevorzugte Lösung wäre so etwas wie dieses ...

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

Im Folgenden finden Modell meine Lösung für 1.0 in MVC binden.

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

Antwort

7

Sie könnten etwas unter den Linien versuchen:

// 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:

Hier ist eine Verbesserung des Bindemittels (TODO Abschnitt in vorherigen Code sehen):

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

In Um Sammlungen zu handhaben Sie das Bindemittel in Application_Start registrieren müssen, wie Sie nicht mehr in der Lage sein werden, die Liste mit den ModelBinderAttribute zu dekorieren:

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

Und dann Ihrer Aktion könnte wie folgt aussehen:

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

Fasst man die wichtige Rolle:

bindingContext.ValueProvider.GetValue(bindingContext.ModelName) 

Eine weitere Verbesserung Schritt dieses Bindemittels wäre Validierung zu handhaben (AddModelErro r/SetModelValue)

+0

Wenn Sie mit einer Liste von MyViewModel beschäftigt ist, ändert das den ModelBinder für die Aktion? öffentlicher ActionResult-Index ([ModelBinder (typeof (CurrencyBinder))] IList Modell) – David

+0

Bitte beachten Sie mein Update. –

Verwandte Themen