2012-07-23 8 views
5

Mis entidades: (el PersonModel debe tener una dirección en AddressOne tipo o AddressTwo (y quizás otros) por lo que el PersonModel tiene un tipo de objeto para el campo de dirección.)Asp.Net MVC 3 Modelo enlace personalizado con objeto variable

public class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
    public string Surname { get; set; } 
    public object Address { get; set; } 
} 

public class AddressOne 
{ 
    public string Street { get; set; } 
    public string City { get; set; } 
} 

public class AddressTwo 
{ 
    public string Province { get; set; } 
    public string State { get; set; } 
} 

los modelos: (I pasa un campo oculto en typeOfAddress para que coincida con la dirección correcta después de que el formulario de envío)

public class PersonModel 
{ 
    private System.Type _typeOfAddress; 
    private object _address; 

    [Required] 
    public int PersonId { get; set; } 
    [Required] 
    public string Name { get; set; } 
    [Required] 
    public string Surname { get; set; } 

    public System.Type typeOfAddress 
    { 
     get { return _typeOfAddress; } 
     set { _typeOfAddress = value; } 
    } 

    public object Address 
    { 
     get { 
      return _address; 
     } 
     set { 
      _address = value; 
      _typeOfAddress = _address.GetType(); 
     } 
    } 
} 

public class AddressOneModel 
{ 
    [Required] 
    public string Street { get; set; } 
    [Required] 
    public string City { get; set; } 
} 

public class AddressTwoModel 
{ 
    [Required] 
    public string Province { get; set; } 
    [Required] 
    public string State { get; set; } 
} 

Mi opinión (para campo de dirección que tengo Editor de plantillas de anuncio que se omite en este código) :

@using (Html.BeginForm()) { 

<ul> 
<li> 
    PersonId: @Html.EditorFor(model => model.PersonId) 
</li> 
<li> 
    Name: @Html.EditorFor(model => model.Name) 
</li> 
<li> 
    Surname: @Html.EditorFor(model => model.Surname) 
</li> 
<li> 
    Address: 
</li> 
<li> 
    @Html.HiddenFor(model => model.typeOfAddress) 
    @Html.EditorFor(model => model.Address) 
</li> 
</ul> 
<button type="submit">Submit</button> 

} 

y luego mi controlador: (en este ejemplo me carga AddressOne en el modelo pero debería haber uno o dos depende en el tiempo de ejecución ...)

[HttpGet] 
    public ActionResult Index() 
    { 
     PersonModel myPerson = new PersonModel(); 

     myPerson.PersonId = 1; 
     myPerson.Name = "Michael"; 
     myPerson.Surname = "Douglas"; 

     AddressOneModel Address = new AddressOneModel(); 
     Address.Street = "5th Avenue"; 
     Address.City = "New York"; 

     myPerson.Address = Address; 

     return View(myPerson); 
    } 

    [HttpPost] 
    public ActionResult Index([ModelBinder(typeof(PersonModelBinder))]PersonModel myPerson) 
    { 
     if (ModelState.IsValid) { 
      // some things here 
     } 
     return View(); 
    } 

entonces no es la carpeta Modelo de PersonModel :

public class PersonModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     PersonModel bindedModel = new PersonModel(); 

     foreach (var Property in typeof(PersonModel).GetProperties()) 
     { 
      PropertyInfo info = bindedModel.GetType().GetProperty(Property.Name); 
      object castedInfo = new object(); 

      var uType = info.PropertyType; 
      if (uType == typeof(string)) 
      { 
       castedInfo = bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue.ToString(); 
      } 
      else if (uType == typeof(Type)) 
      { 
       castedInfo = Type.GetType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue.ToString()); 
      } 
      else if (uType == typeof(object)) 
      { 
       string objType = bindingContext.ValueProvider.GetValue("typeOfAddress").AttemptedValue; 
       object address = (object)Activator.CreateInstance(Type.GetType(objType)); 

       // another foreach as previous 
      } 
      else 
      { 
       object uCasted = (object)Activator.CreateInstance(info.PropertyType); 
       uCasted = Convert.ChangeType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue, Property.PropertyType); 
       castedInfo = uCasted; 
      } 
      info.SetValue(bindedModel, castedInfo, null); 
     } 
     return bindedModel; 
    } 

¿Es esta la manera correcta de implementar el enlace de PersonModel? ¿Y qué hay de la validación en el controlador [Post]?

También vi una manera de utilizar DefaultBinder de una manera como esto:

[ModelBinderType(typeof(PersonModel))] 
public class PersonModelBinder : DefaultModelBinder 
{ 
    //... 
} 

pero yo no encuentro ninguna referencia de ModelBinderType en MVC3 !! ¿Cualquier sugerencia?

Respuesta

2

Parece que estás tratando de hacer esto de la manera difícil. No deberías necesitar una carpeta modelo. Lo que haría es agregar cada tipo de dirección al modelo y en la página mostrar el que no es nulo. Esto te ahorraría muchas molestias.

public class PersonModel : IValidatableObject 
{ 
    private System.Type _typeOfAddress; 
    private object _address; 

    [Required] 
    public int PersonId { get; set; } 
    [Required] 
    public string Name { get; set; } 
    [Required] 
    public string Surname { get; set; } 

    public System.Type typeOfAddress 
    { 
     get { return (AddressOne ?? AddressTwo ?? AddressThree).GetType(); } 
    } 

    public AdressOneModel AddressOne {get;set;} 
    public AdressTwoModel AddressTwo {get;set;} 
    public AdressThreeModel AddressThree {get;set;} 
} 

Entonces tal vez en la página de hacer esto

@using (Html.BeginForm()) 
{ 
    <ul> 
    <li> 
     PersonId: @Html.EditorFor(model => model.PersonId) 
    </li> 
    <li> 
     Name: @Html.EditorFor(model => model.Name) 
    </li> 
    <li> 
     Surname: @Html.EditorFor(model => model.Surname) 
    </li> 
    <li> 
     Address: 
    </li> 
    <li> 
    @if(model.AddressOne != null) 
    { 
     Html.EditorFor(model => model.AddressOne) 
    } 
    else if(model.AddressTwo != null) 
    { 
     Html.EditorFor(model => model.AddressTwo) 
    } 
    </li> 
    </ul> 
    <button type="submit">Submit</button> 
} 

Pero lo que realmente depende de por qué estás haciendo esto

Cuestiones relacionadas