2010-03-16 3 views
5

모델 바인딩 기능을 만들고 싶습니다. 사용자가 ',' '을 입력 할 수 있습니다.' 내 ViewModel의 double 값에 바인딩하는 통화 값에 대한 등.asp.net MVC 1.0 및 2.0 통화 모델 바인딩

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

답변

7

당신은 선 사이에서 뭔가를 시도 할 수 있습니다 :

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

바인더의 개선이다 (이전 코드에서 TODO 섹션 참조)

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

있음

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(); 
} 
더 이상하여 ModelBinderAttribute와 목록을 장식 할 수 없습니다 당신이 Application_Start에 바인더를 등록해야합니다 컬렉션을 처리하기 위해

요약 중요한 부분 :

bindingContext.ValueProvider.GetValue(bindingContext.ModelName) 

이 바인더의 또 다른 개선 단계 (검증을 처리하는 것 AddModelErro r/SetModelValue)

+0

MyViewModel 목록을 다루는 경우 동작에 대한 ModelBinder가 변경됩니까? public ActionResult 인덱스 (ModelBinder (typeof (CurrencyBinder))] IList 모델 – David

+0

내 업데이트를 참조하십시오. –