I have a base class, a set of subclasses and a collection container that I am using to create and populate controls dynamically using partial views.
// base class
public class SQControl
{
[Key]
public int ID { get; set; }
public string Type { get; set; }
public string Question { get; set; }
public string Previous { get; set; }
public virtual string Current { get; set; }
}
// subclass
public class SQTextBox : SQControl
{
public SQTextBox()
{
this.Type = typeof(SQTextBox).Name;
}
}
//subclass
public class SQDropDown : SQControl
{
public SQDropDown()
{
this.Type = typeof(SQDropDown).Name;
}
[UIHint("DropDown")]
public override string Current { get; set; }
}
// collection container used as the Model for a view
public class SQControlsCollection
{
public List<SQControl> Collection { get; set; }
public SQControlsCollection()
{
Collection = new List<SQControl>();
}
}
I populate the Collection control with different subclasses of SQControl as required at runtime, and in EditorTemplates I have a separate view for each subclass. Using Html.EditorFor on the collection items I can dynamically generate the form with the appropriate controls.
This all works fine.
The problem I have is that when I save the form, MVC binding cannot tell what subclass each item in the Collection was created with and instead bind them to instances of the base class SQControl.
This confuses the View engine as it cannot determine the proper views to load anymore and simply loads the default.
The current workaround I have is to save the "Type" of the subclass as a field in the model, and on postback, I copy the collection into a new container, re-creating each object with the proper subclass based on the information in the Type field.
public static SQControlsCollection Copy(SQControlsCollection target)
{
SQControlsCollection newCol = new SQControlsCollection();
foreach (SQControl control in target.Collection)
{
if (control.Type == "SQTextBox")
{
newCol.Collection.Add(new SQTextBox { Current = control.Current, Previous = control.Previous, ID = control.ID, Question = control.Question });
}
else if (control.Type == "SQDropDown")
{
newCol.Collection.Add(new SQDropDown { Current = control.Current, Previous = control.Previous, ID = control.ID, Question = control.Question });
}
...
}
return newCol;
}
So my Question is, is there any better way to maintain the type of items in a base-typed-collection between postbacks? I understand it's practice in MVC to have a typed view for each model, but I want to be able to build a view on the fly based on an XML document using reusable partial views.