2009-07-02 2 views
1

Я следующий маршрут:Привязка routevalue к свойству объекта, который является частью ViewModel

  routes.MapRoute(
      "Default",            // Route name 
      "{controller}/{action}/{id}",       // URL with parameters 
      new { controller = "Home", action = "Index", id = "" } // Parameter defaults 
     ); 

и я использую ViewModel:

namespace MvcApplication1.Models 
{ 
    public class ProductViewModel 
    { 

     public ProductViewModel() 
     { 
      ProductDetail = new ProductInfo(); 
     } 

     public ProductInfo ProductDetail { get; set; } 

    } 

    public class ProductInfo 
    { 
     public string Name { get; set; } 
     public int ProductID { get; set; } 
    } 

} 

Мне нужен способ, чтобы привязать идентификатор параметра маршрута к Model.ProductDetail.ProductID.

/Продукты/Дисплей/2 должно привести к:

Model.ProductDetail.ProductID == 2

Я знаю, это выглядит немного странно: Было бы намного проще, если бы мой ViewModel будет только

класса ProductViewModel общественного {общественного ИНТ Id {получить; набор;}}

для обработки партиалов я предпочитаю использовать агрегацию. Я действительно не могу иметь ID в основном классе ViewModel.

Я довольно уверен, что мне нужно реализовать свой собственный ModelBinder, но я не вижу, где я должен реализовывать свои собственные правила.

Как я могу сопоставить параметр маршрута «id» с свойством Model.ProductDetail.ProductID?

EDIT:

Вот как его сделали -

public class ProductModelBinder: DefaultModelBinder 
{ 
    protected override void BindProperty(
     ControllerContext controllerContext, 
     ModelBindingContext bindingContext, 
     System.ComponentModel.PropertyDescriptor propertyDescriptor 
     ) { 
      if (bindingContext.ModelType == typeof(ProductViewModel) 
      && String.Compare(propertyDescriptor.Name, "ProductDetail", true) == 0)  
      {   
       int id = int.Parse((string)controllerContext.RouteData.Values["id"]); 
       ProductViewModel productView = bindingContext.Model as ProductViewModel; 
       productView.ProductDetail.ProductID = id;   
       return;  
     }  
     base.BindProperty(controllerContext, bindingContext, propertyDescriptor); } 
} 
+0

Но это не заполнит productView.ProductDetail.Name, или что-либо еще в ViewModel. Это в основном даст вам бесполезный объект ProductViewModel, поскольку заполняется только идентификатор. – Jason

+0

Я предполагаю, что мой пример не так хорош. В реальном приложении мне нужен только идентификатор в ProductDetail. Другие свойства заполняются внутри контроллера путем обращения к репозиторию. –

+0

Лучшей практикой будет: ActionResult Details (int id) {return View (новый ProductViewModel (db.GetProductInfo (id))); } – Jason

ответ

1

Попробуйте что-то вроде этого (не проверено):

public class CustomModelBinder : DefaultModelBinder 
{ 
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor) 
    { 
     if (bindingContext.ModelType == typeof(ProductInfo) 
      && String.Compare(propertyDescriptor.Name, "ProductID", true) == 0) 
     { 
      var id = (int)controllerContext.RouteData.Values["id"]; 

      var productInfo = bindingContext.Model as ProductInfo; 

      productInfo.ProductID = id; 

      return; 
     } 

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

Спасибо, Евгений. Это сработало. Мне пришлось создать ModelBinder для ProductViewModel. Вы указали связующее для ProductInfo. Я не уверен, могу ли я зарегистрировать связующее для подобъекта. В любом случае, это работает для меня, как показано в обновленном сообщении. –