2009-12-16 38 views
9

Tôi có một loạt các biểu mẫu nơi nhập các giá trị tiền tệ và tôi muốn chúng có thể nhập "$ 1,234.56". Theo mặc định, trình kết nối mô hình sẽ không phân tích cú pháp đó thành số thập phân.Làm cách nào để lọc dữ liệu biểu mẫu bằng mô hình liên kết tùy chỉnh

Điều tôi đang nghĩ là tạo mô hình tùy chỉnh kết nối phần thừa kế DefaultModelBinder, ghi đè phương thức BindProperty, kiểm tra xem kiểu mô tả thuộc tính có phải là số thập phân hay không, chỉ cần bỏ ra $ và, từ các giá trị.

Đây có phải là cách tiếp cận tốt nhất không?

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

Cập nhật

Đây là những gì tôi đã kết thúc thực hiện:

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

hãy nhìn vào bài đăng này từ Haacked: http://haacked.com/archive/2011/03/ 19/fixing-binding-to-decimals.aspx – VinnyG

Trả lời

5

Đó là hợp lý để làm điều đó trong các chất kết dính. Tuy nhiên, tôi nghĩ rằng Decimal.Parse với nhà cung cấp định dạng tiền tệ hoặc kiểu số (see the docs) sẽ đáng tin cậy hơn là loại bỏ "$" và gọi số base. Đối với người mới bắt đầu, nó sẽ xử lý tiền tệ không phải của Mỹ, có thể là một vấn đề cho bạn một số ngày.

+1

Rất tiếc. Không biết Decimal.Parse có định dạng sẽ chấp nhận định dạng đó theo mặc định. Bạn sẽ nghĩ rằng sẽ có một cách để mô hình liên kết chấp nhận điều đó theo mặc định sau đó. Trên thực tế, trên ví dụ này http://www.asp.net/%28S%28ywiyuluxr3qb2dfva1z5lgeg%29%29/learn/mvc/tutorial-39-cs.aspx, chúng thậm chí có loại thập phân với trình xác thực regex có giá $ ok ... Nếu tôi có loại thập phân, giá trị là $ 1,234 hoặc $ 1234 là 0 và trạng thái mô hình không hợp lệ. –

+0

Tôi đã xem qua nguồn MVC và nguồn DataAnnotationsModelBinder, và tôi nghĩ tốt nhất nên gọi cơ sở. Có rất nhiều thứ đang diễn ra, bao gồm xử lý các lỗi và trạng thái mô hình. Tôi nghĩ làm những gì tôi đã làm trước đây, nhưng sử dụng hàm thập phân.Parse thay vào đó sẽ hoạt động tốt. –

1

Bạn có thể tạo ValidationAttribute của riêng mình để kiểm tra xem giá trị có định dạng đúng hay không. Sau đó, bạn có thể xem nếu tài sản được trang trí với thuộc tính này và ràng buộc nó theo cách thích hợp. Thuộc tính không cần phải là ValidationAttibute, nhưng nó có vẻ là ý tưởng hay.

5

Trong MVC3 bạn chỉ có thể đăng ký một modelbinder tùy chỉnh thực hiện giao diện IModelBinder dành riêng cho các loại thập phân và sau đó yêu cầu nó xử lý tiền tệ hoặc số thập phân bằng cách sử dụng thuộc tính ModelMetaData.DataTypeName trên bindingContext.

Tôi đã sửa đổi các mẫu được cung cấp bởi Phil Haack in his article để chứng minh làm thế nào nó có thể được thực hiện:

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; 
     } 
    } 
Các vấn đề liên quan