2009-07-02 1 views
1

Ich habe die folgende Route:eines Objekts, das Teil von Viewmodel ist

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

und ich verwende das Ansichtsmodell:

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

} 

Ich muss einen Weg das binden Parameter-ID der Route zu Model.ProductDetail.ProductID.

/Produkte/Anzeige/2 sollte führen:

Model.ProductDetail.ProductID == 2

Ich weiß, das ein bisschen seltsam aussieht: Es wäre viel einfacher, wenn mein Viewmodel nur

sei

public class ProductViewModel {public int Id {get; set;}}

Für Aggregation partials ich ziehe es verwenden Handhabung. Ich kann wirklich keine ID in der ViewModel Hauptklasse haben.

Ich bin mir ziemlich sicher, dass ich meinen eigenen ModelBinder implementieren muss, aber ich sehe nicht, wo ich meine eigenen Regeln implementieren soll.

Wie kann ich den Routenparameter "id" der Eigenschaft Model.ProductDetail.ProductID zuordnen?

EDIT:

Hier ist, wie ihre getan -

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

Aber das wird productView.ProductDetail.Name nicht füllen, oder irgendetwas anderes im ViewModel. Es wird Ihnen im Grunde ein nutzloses ProductViewModel-Objekt geben, da nur die ID ausgefüllt ist. – Jason

+0

Ich denke, mein Beispiel ist nicht so nett. In der realen Anwendung benötige ich nur die ID in ProductDetail. Die anderen Eigenschaften werden innerhalb des Controllers durch Zugriff auf das Repository gefüllt. –

+0

Eine bessere Vorgehensweise wäre: ActionResult Details (int id) {return View (neues ProductViewModel (db.GetProductInfo (id))); } – Jason

Antwort

1

Versuchen Sie so etwas (nicht getestet):

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

Danke eugene. Das hat funktioniert. Ich musste einen ModelBinder für ProductViewModel erstellen. Sie haben den Ordner für ProductInfo angezeigt. Ich bin mir nicht sicher, ob ich einen Ordner für ein Unterobjekt registrieren kann. Wie auch immer, es funktioniert für mich wie im aktualisierten Beitrag gezeigt. –