Reputation: 4623
I'm trying to clean up some pretty ugly form population code in the code behind of an aspx that looks like this:
SchoolCensus1.Checked = (bool)questions[0].SchoolCensus1;
SchoolCensus1Info.Text = questions[0].SchoolCensus1Info;
SchoolCensus2.Checked = (bool)questions[0].SchoolCensus2;
SchoolCensus2Info.Text = questions[0].SchoolCensus2Info;
SchoolCensus3.Checked = (bool)questions[0].SchoolCensus3;
SchoolCensus3Info.Text = questions[0].SchoolCensus3Info;
This goes on for quite a while.
What I have so far is this:
Type questionsType = questions[0].GetType();
PropertyInfo[] properties = questionsType.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(Nullable<Boolean>))
{
CheckBox chkBox = container.FindControl(property.Name) as CheckBox;
if (chkBox != null)
chkBox.Checked = (bool)property.GetValue(questions[0], null);
}
else if (property.PropertyType == typeof(String))
{
TextBox txtBox = container.FindControl(property.Name) as TextBox;
if (txtBox != null)
txtBox.Text = (string)property.GetValue(questions[0], null);
}
}
This does what I need it to do, but I want to break out this part into a method to DRY it up a little more:
TextBox txtBox = container.FindControl(property.Name) as TextBox;
if (txtBox != null)
txtBox.Text = (string)property.GetValue(questions[0], null);
Any advice as to the method needed to cope with the changing Control type? I'm guessing generics is what I need, but that really isn't something I have much experience in.
Thanks in advance!
Upvotes: 0
Views: 2001
Reputation: 4186
Be careful what you wish for...
No error control whatsoever, but here goes the generics version of your 2nd code block.
static class ControlAssign
{
public static void Assign(Control target, object source, PropertyInfo prop)
{
Setters[prop.PropertyType](prop, source, target);
}
static ControlAssign()
{
Setters[typeof(string)] = (prop, src, target) =>
{
((TextBox)target).Text =
(string)prop.GetValue(src, null);
};
Setters[typeof(bool?)] = (prop, src, target) =>
{
((CheckBox)target).Checked =
(bool)prop.GetValue(src, null);
};
Setters[typeof(bool)] = (prop, src, target) =>
{
((CheckBox)target).Checked =
(bool)prop.GetValue(src, null);
};
}
public delegate void Action<T, U, V>(T t, U u, V v);
readonly static Dictionary<Type, Action<PropertyInfo, object, Control>> Setters = new Dictionary<Type, Action<PropertyInfo, object, Control>>();
}
Upvotes: 2
Reputation: 6952
One of the projects I worked with solved the problem by
Every control of a different type will need different treatment. I am not sure how you can use generics to have a common method to populate for example a TextBox and a CheckBox.
Also, I notice that you are making a decision on the type of control used based on the property type. i.e. to say that all properties of type "string" map to a TextBox. But in the future you might very well want to bind a string property to a Label.
Instead of deciding the control type based on the property, you should do something like this...
foreach (PropertyInfo property in properties)
{
Control ctrl = container.FindControl(property.Name);
if (ctrl != null)
{
if (ctrl is TextBox)
{
((TextBox)ctrl).Text = (string)property.GetValue(questions[0], null);
}
else if (ctrl is Label)
{
((Label)ctrl).Text = (string)property.GetValue(questions[0], null);
}
else if (ctrl is CheckBox)
{
(CheckBox)ctrl).Checked = (bool)property.GetValue(questions[0], null);
}
// etc.. for each control type
}
}
Upvotes: 1