Cómo crear controles dinámicamente en MVC 3 basado en un archivo XML

Tengo un archivo XML almacenado en la base de datos como formato XML que contiene algunos controles como el cuadro de texto desplegable, el área de texto de la etiqueta, etc. que pueden tener o no valores iniciales. Así que mi objective es leer el archivo XML y, en función del tipo de control, necesito crear ese control dinámicamente y asociar el valor inicial, si lo hay, y la vista previa de la página debe mostrarse en una vista. Cualquiera, por favor, ayúdenme a crear los controles dinámicamente en MVC 3 para este escenario.

Por ejemplo: mi archivo xml se verá algo así.

      . . .       . . .   . . .  

Gracias por adelantado.

Trataré de ofrecerte algunos consejos que podrían darte algunas ideas.

Como siempre comencemos definiendo un modelo de vista que representará la IU:

 public class MyViewModel { public ControlViewModel[] Controls { get; set; } } public abstract class ControlViewModel { public abstract string Type { get; } public bool Visible { get; set; } public string Label { get; set; } public string Name { get; set; } } public class TextBoxViewModel : ControlViewModel { public override string Type { get { return "textbox"; } } public string Value { get; set; } } public class CheckBoxViewModel : ControlViewModel { public override string Type { get { return "checkbox"; } } public bool Value { get; set; } } public class DropDownListViewModel : TextBoxViewModel { public override string Type { get { return "ddl"; } } public SelectList Values { get; set; } } 

Así que hemos definido algunos de los controles básicos que nos gustaría manejar en nuestra aplicación. El siguiente paso sería tener un método de repository que consultará la base de datos, buscará el XML y luego una capa de mapeo que finalmente nos proporcionará una instancia de nuestro modelo de vista. Dejo esto fuera del scope de esta respuesta, ya que hay muchas formas de implementarlo (XmlSerializer, XDocument, XmlReader, …).

Supongo que ya tienes una instancia del modelo de vista. Me gusta esto:

 public ActionResult Index() { var model = new MyViewModel { Controls = new ControlViewModel[] { new TextBoxViewModel { Visible = true, Label = "label 1", Name = "TextBox1", Value = "value of textbox" }, new CheckBoxViewModel { Visible = true, Label = "check label", Name = "CheckBox1", Value = true }, new DropDownListViewModel { Visible = true, Label = "drop label", Name = "DropDown1", Values = new SelectList( new[] { new { Value = "1", Text = "text 1" }, new { Value = "2", Text = "text 2" }, new { Value = "3", Text = "text 3" }, }, "Value", "Text", "2" ) } } }; return View(model); } 

Así que he codificado algunos valores para ilustrar el concepto, pero normalmente esta acción del controlador se vería algo así una vez que implementes el repository y la capa de mapeo:

 public ActionResult Index() { string xml = _repository.GetControls(); var model = Mapper.Map(xml); return View(model); } 

OK, ahora vayamos a la vista Index.cshtml correspondiente que contendrá el formulario:

 @model MyViewModel @using (Html.BeginForm()) { for (int i = 0; i < Model.Controls.Length; i++) { if (Model.Controls[i].Visible) { 
@Html.HiddenFor(x => x.Controls[i].Type) @Html.HiddenFor(x => x.Controls[i].Name) @Html.EditorFor(x => x.Controls[i])
} } }

OK, entonces ahora podemos definir las plantillas de editor correspondientes para los controles que nos gustaría manejar:

  • ~/Views/Shared/EditorTemplates/TextBoxViewModel.cshtml

     @model AppName.Models.TextBoxViewModel @Html.LabelFor(x => x.Value, Model.Label) @Html.TextBoxFor(x => x.Value) 
  • ~/Views/Shared/EditorTemplates/CheckBoxViewModel.cshtml

     @model AppName.Models.CheckBoxViewModel @Html.CheckBoxFor(x => x.Value) @Html.LabelFor(x => x.Value, Model.Label) 
  • ~/Views/Shared/EditorTemplates/DropDownListViewModel.cshtml

     @model AppName.Models.DropDownListViewModel @Html.LabelFor(x => x.Value, Model.Label) @Html.DropDownListFor(x => x.Value, Model.Values) 

Hasta aquí todo bien. En esta etapa, debería poder representar un formulario que contenga los controles dynamics. Pero, por supuesto, esa forma es bastante inútil para cualquiera. Lo que sería bueno es tener la posibilidad de PUBLICAR este formulario y capturar los valores ingresados ​​por el usuario en una acción de controlador para que podamos procesarlos.

La acción del controlador se vería así:

 [HttpPost] public ActionResult Index(MyViewModel model) { ... process the values } 

Ahora eso sería bueno, pero por supuesto no funcionará porque el modelo de vista ControlViewModel es una clase abstracta y la carpeta de modelo predeterminada no tiene ni idea de qué implementación específica crear. Entonces, tenemos que ayudarlo escribiendo una carpeta de modelo personalizada:

 public class ControlModelBinder : DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) { var type = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type"); object model = null; switch (type.AttemptedValue) { case "textbox": { model = new TextBoxViewModel(); break; } case "checkbox": { model = new CheckBoxViewModel(); break; } case "ddl": { model = new DropDownListViewModel(); break; } default: { throw new NotImplementedException(); } }; bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()); return model; } } 

que se registrará en Application_Start y se asociará al tipo ControlViewModel ):

 ModelBinders.Binders.Add(typeof(ControlViewModel), new ControlModelBinder()); 

Parece ser bastante simple de hecho. Obtenga su XML de la base de datos, analícelo y póngalo en algunas clases modelo. Esa voluntad clasificada contiene datos de controles.

A continuación, cree una vista parcial que construirá dinámicamente los controles requeridos según el modelo.

Al final, llame esa acción desde jQuery ajax y coloque el HTML devuelto en el lugar correcto.

Rápido, fácil, no reaload ….

puede pasar un modelo a su vista fuertemente tipada y escribir un helper html llamado Html.ControlFor en el helper puede leer el archivo xml y crear controles (entrada, seleccionar etc.) en función del nombre de la propiedad (donde el nombre de propiedad coincide con la etiqueta de propiedad en el archivo xml)