Dire que j'ai un modèle de Produit, le modèle de Produit a une propriété de ProductSubType (abstrait) et nous avons deux des implémentations concrètes Chemise et un Pantalon.
Voici la source:
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public decimal? Price { get; set; }
[Required]
public int? ProductType { get; set; }
public ProductTypeBase SubProduct { get; set; }
}
public abstract class ProductTypeBase { }
public class Shirt : ProductTypeBase
{
[Required]
public string Color { get; set; }
public bool HasSleeves { get; set; }
}
public class Pants : ProductTypeBase
{
[Required]
public string Color { get; set; }
[Required]
public string Size { get; set; }
}
Dans mon INTERFACE, l'utilisateur dispose d'une liste déroulante permet de sélectionner le type de produit et les éléments d'entrée sont affichés selon le droit type de produit. J'ai tout compris (à l'aide d'un ajax obtenir sur la liste déroulante changer, retour partiel/éditeur de modèle et de ré-installation de jquery validation en conséquence).
Ensuite, j'ai créé un modèle de liaison personnalisé pour ProductTypeBase.
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ProductTypeBase subType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1)
{
var shirt = new Shirt();
shirt.Color = (string)bindingContext.ValueProvider.GetValue("SubProduct.Color").ConvertTo(typeof(string));
shirt.HasSleeves = (bool)bindingContext.ValueProvider.GetValue("SubProduct.HasSleeves").ConvertTo(typeof(bool));
subType = shirt;
}
else if (productType == 2)
{
var pants = new Pants();
pants.Size = (string)bindingContext.ValueProvider.GetValue("SubProduct.Size").ConvertTo(typeof(string));
pants.Color = (string)bindingContext.ValueProvider.GetValue("SubProduct.Color").ConvertTo(typeof(string));
subType = pants;
}
return subType;
}
}
Cette lie les valeurs correctement et fonctionne pour la plupart, sauf que je perds le côté serveur de validation. Donc, sur une intuition que j'ai fais une erreur j'ai fait quelques recherches et suis tombé sur cette réponse par Darin Dimitrov:
ASP.NET MVC 2 - Liaison De Modèle Abstrait
J'ai donc changé le modèle de classeur remplacer que CreateModel, mais maintenant il ne se lient pas les valeurs.
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
ProductTypeBase subType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1)
{
subType = new Shirt();
}
else if (productType == 2)
{
subType = new Pants();
}
return subType;
}
Stepping bien que le MVC 3 src, il semble que dans BindProperties, le GetFilteredModelProperties retourne un résultat vide, et je pense que parce que bindingcontext modèle est défini à ProductTypeBase qui n'ont pas de propriétés.
Quelqu'un peut-il repérer ce que je fais de mal? Cela ne semble pas comme il devrait être, cela est difficile. Je suis sûr que je suis absent quelque chose de simple...j'ai une autre alternative à l'esprit, au lieu d'avoir un SubProduct propriété dans le modèle de Produit pour seulement ont des propriétés distinctes pour la Chemise et le Pantalon. Ce sont juste View/les modèles à Forme donc je pense que cela fonctionnerait, mais souhaitez obtenir de l'approche actuelle de travail, voire rien, pour comprendre ce qui se passe...
Merci pour toute aide!
Mise à jour:
Je n'ai pas préciser, mais le modèle de classeur que j'ai ajouté, hérite de la DefaultModelBinder
Réponse
Réglage ModelMetadata et le Modèle était la pièce manquante. Merci De Manas!
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
if (modelType.Equals(typeof(ProductTypeBase))) {
Type instantiationType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1) {
instantiationType = typeof(Shirt);
}
else if (productType == 2) {
instantiationType = typeof(Pants);
}
var obj = Activator.CreateInstance(instantiationType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
bindingContext.ModelMetadata.Model = obj;
return obj;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}