views:

81

answers:

2

Hi,

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!

+1  A: 

One of the projects I worked with solved the problem by

  1. Mapping Properties with Field in XML Configuration Files
  2. Defining a generic Method that would populate every field with its corresponding property. This would involve:
    • load all data from the current aspx page from the config file
    • for each control in the list, find it on the page and update its value

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
    }
}
Preets
Ahh yeah, switching it around to the type of control rather than the data source does make sense in the long run. Cheers!
DavidGouge
+2  A: 

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>>();
}
Florian Doyon
Interesting solution, I like it!
DavidGouge