在ASP.NET中, 我们要获取控件的值, 或是给控件赋值, 一般都是Control.Property = Entity.Property, Entity.Property = Control.Property.
如果控件太多,这样写就显的繁琐,而且容易出错.
这种情况下, 使用反射, 把符合控件名和实体属性名相同的值相互映射,只要一行代码就可以完成操作了.

来看主要的两个方法签名:

        /// <summary>
       
/// 将控件的值映射到实体
       
/// </summary>
       
/// <param name="container">映射的控件的容器控件</param>
       
/// <param name="obj">实体</param>
       
/// <param name="isContainChildren">是否遍历子控件</param>
       
/// <param name="controlIDFormat">控件ID的格式, {0}表示值的名称</param>
       
/// <param name="customMaps">自定义的[属性-值]映射规则, Key=控件属性名, Value=属性类型</param>
        public static void ControlsToEntity(Control container, object entity, bool isContainChildren, string controlIDFormat, params KeyValuePair<string, Type>[] customMaps)

       
/// <summary>
       
/// 将实体属性值映射到控件
       
/// </summary>
       
/// <param name="entity">实体</param>
       
/// <param name="container">映射的控件的容器控件</param>
       
/// <param name="isContainChildren">是否遍历子控件</param>
       
/// <param name="idFormat">控件ID的格式, {0}表示值的名称</param>
       
/// <param name="customMaps">自定义的[属性-值]映射规则, Key=控件属性名, Value=属性类型</param>
        public static void EntityToControls(object entity, Control container, bool isContainChildren, string controlIDFormat, params KeyValuePair<string, Type>[] customMaps)


然后是测试用例, 不太容易理解, 见谅:

    public class Entity
   
{
       
public bool CheckBoxControl { get; set; }
       
public string TextBoxControl { get; set; }
       
public string LabelControl { get; set; }
       
public object OtherControl { get; set; }
       
public int DropDownListControl { get; set; }
       
public int? ListBoxControl { get; set; }
       
public string CustomControl { get; set; }
    }


   
public class Custom : Control
   
{
       
public string CustomProperty { get; set; }
    }


    [TestClass()]
   
public class ControlMappingTest
   
{
        [TestMethod()]
       
public void TestEntityControlsMapping()
       
{
            Entity entity
= new Entity()
           
{
                CheckBoxControl
= true,
                ListBoxControl
= 1,
                DropDownListControl
= 1,
                LabelControl
= "LabelValue",
                TextBoxControl
= "TextBoxValue",
                CustomControl
= "CustomValue",
            }
;

           
#region 控件

            CheckBox CheckBoxControl
= new CheckBox() { ID = "_CheckBoxControl" };
            ListBox ListBoxControl
= new ListBox() { ID = "_ListBoxControl" };
            ListBoxControl.Items.Add(
new ListItem("", "0"));
            ListBoxControl.Items.Add(
new ListItem("", "1"));
            DropDownList DropDownListControl
= new DropDownList() { ID = "_DropDownListControl" };
            DropDownListControl.Items.Add(
new ListItem("", "0"));
            DropDownListControl.Items.Add(
new ListItem("", "1"));
            Label LabelControl
= new Label() { ID = "_LabelControl" };
            TextBox TextBoxControl
= new TextBox() { ID = "_TextBoxControl" };
            Custom CustomControl
= new Custom() { ID = "_CustomControl" };

            Control container
= new Control();
            container.Controls.Add(CheckBoxControl);
            container.Controls.Add(ListBoxControl);
            container.Controls.Add(
new TextBox() { ID = "txt" });
            container.Controls.Add(LabelControl);
            container.Controls.Add(CustomControl);

            Panel tempPanel
= new Panel() { ID = "_tempPanel" };
            tempPanel.Controls.Add(TextBoxControl);
            tempPanel.Controls.Add(
new TextBox() { ID = "ttt" });
            tempPanel.Controls.Add(DropDownListControl);
            container.Controls.Add(tempPanel);

           
#endregion

           
bool isContainChildren = true;

           
//实体 -> 控件
            KeyValuePair<string, Type> customMaps = new KeyValuePair<string, Type>("CustomProperty", typeof(string));
            ControlMapping.EntityToControls(entity, container, isContainChildren,
"_{0}", customMaps);

            Assert.AreEqual(entity.CheckBoxControl, CheckBoxControl.Checked);
            Assert.AreEqual(entity.TextBoxControl, TextBoxControl.Text);
            Assert.AreEqual(entity.LabelControl, LabelControl.Text);
            Assert.AreEqual(entity.DropDownListControl, Converters.ChangeType
<int>(DropDownListControl.SelectedValue));
            Assert.AreEqual(entity.ListBoxControl, Converters.ChangeType
<int>(ListBoxControl.SelectedValue));
            Assert.AreEqual(entity.CustomControl, CustomControl.CustomProperty);

           
//控件 -> 实体
            entity = new Entity();
            ControlMapping.ControlsToEntity(container, entity, isContainChildren,
"_{0}",  customMaps);

            Assert.AreEqual(entity.CheckBoxControl, CheckBoxControl.Checked);
            Assert.AreEqual(entity.TextBoxControl, TextBoxControl.Text);
            Assert.AreEqual(entity.LabelControl, LabelControl.Text);
            Assert.AreEqual(entity.DropDownListControl, Converters.ChangeType
<int>(DropDownListControl.SelectedValue));
            Assert.AreEqual(entity.ListBoxControl,Converters.ChangeType
<int>( ListBoxControl.SelectedValue));
            Assert.AreEqual(entity.CustomControl, CustomControl.CustomProperty);
        }

    }



之后我又有了新的想法, 就是在中间加入一层Hash值, 这样就可以实现UI层的解藕, 即Control <=> Hash <=> Entity.
暂时只实现了Control <=> Hash :
        /// <summary>
       
/// 将控件值映射到Hash表
       
/// </summary>
       
/// <param name="container">映射控件的容器控件</param>
       
/// <param name="isContainChildren">是否遍历子控件</param>
       
/// <param name="customMaps">自定义的控件属性</param>
        public static Dictionary<string, object> ControlsToHash(Control container, bool isContainChildren, params
string[] customProperties)

       
/// <summary>
       
/// 将Hash表值映射到控件
       
/// </summary>
       
/// <param name="hash">Hash键值对</param>
       
/// <param name="container">映射控件的容器控件</param>
       
/// <param name="isContainChildren">是否遍历子控件</param>
        public static void HashToControls(Dictionary<string, object> hash, Control container, bool isContainChildren, params string[] customProperties)


测试用例:

        [TestMethod]
       
public void ControlsToHashAndHashToControlsTest()
       
{
           
#region 测试数据准备

            Control container
= new Control();

            Label c_UserID
= new Label() { ID = "c_UserID" };
            TextBox c_UserName
= new TextBox() { ID = "c_UserName" };

            Control otherInfo
= new Control();
            DropDownList c_Age
= new DropDownList() { ID = "c_Age" };
            c_Age.Items.Add(
new ListItem("1"));
            DropDownList c_IsUsed
= new DropDownList() { ID = "c_IsUsed" };
            c_IsUsed.Items.Add(
new ListItem("True"));
            otherInfo.Controls.Add(c_Age, c_IsUsed);

            RadioButtonList c_RoleID
= new RadioButtonList() { ID = "c_RoleID" };
            c_RoleID.Items.Add(
new ListItem("2"));

            container.Controls.Add(c_UserID, c_UserName, otherInfo, c_RoleID);

           
#endregion

            Dictionary
<string, object> expectedHash = new Dictionary<string, object>();
            expectedHash.Add(
"c_UserID", "1");
            expectedHash.Add(
"c_UserName", "Xiaosonl");
            expectedHash.Add(
"c_Age", "1");
            expectedHash.Add(
"c_IsUsed", "True");
            expectedHash.Add(
"c_RoleID", "2");

            ControlMapping.HashToControls(expectedHash, container,
true);

            Dictionary
<string, object> hash = ControlMapping.ControlsToHash(container, false);
            Assert.AreEqual(
false, hash.SerializeEqual(expectedHash));
            hash
= ControlMapping.ControlsToHash(container, true);
            Assert.AreEqual(
true, hash.SerializeEqual(expectedHash));
        }


具体实现代码见FastDev.Web.ControlMapping类.