在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类.
如果控件太多,这样写就显的繁琐,而且容易出错.
这种情况下, 使用反射, 把符合控件名和实体属性名相同的值相互映射,只要一行代码就可以完成操作了.
来看主要的两个方法签名:
/// <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, paramsstring[] 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类.

添加至收藏夹