用户界面的可配置解决方案
.net的反射以及用户界面的可配置性在一段200行的代码中体现的淋漓尽致。
只需要两个类,两个配置文件。
首先看一下配置文件的结构吧。
ControlColor.xml中定义了控件的名称、种类以及颜色。
<Control>
<ControlType>SwitchTextLabel</ControlType>
<ControlName>TxtPassword</ControlName>
<Color>black,yellow,pink,white</Color>
</Control>
ControlType.xml中定义了控件的类型、颜色属性以及对应的lib库。
<Control>
<ControlType>SwitchTextLabel</ControlType>
<Lib>switchtextlabel.dll</Lib>
<Property>TextBackColor</Property>
<Property>TextForeColor</Property>
<Property>LabelBackColor</Property>
<Property>LabelForeColor</Property>
</Control>
剩余的就是两个类了,其实是很简单的东西。XmlReader就是能把这两个XML文件正确的对应起来并能够准确的取出相应值的类。
重要的是FormUtil这个类。
方法getAllSubControls()就是得到某一个控件内所有的子控件,递归实现的。
看方法setObjProperty。
2 string[] color = colorList[1].ToString().Split(',');
3 string[] property = propertyList[0].ToString().Split(',');
4 string lib = propertyList[1].ToString();
5
6 Type tp = System.Type.GetType(type);
7 if (tp == null)
8 {
9 Assembly ass = Assembly.LoadFrom(lib);//这个lib就是配置文件ControlType.xml中的Lib
10 tp = ass.GetType(type, true, true);
11 }
12
13 for (int i = 0; i < color.Length; i++)
14 {
15 if (property.Length > i)
16 {
17 if (property[i] != "")
18 {
19 Object[] args = new object[1];
20 args[0] = Color.FromName(color[i]);
21
22 tp.InvokeMember(property[i], BindingFlags.Public | BindingFlags.Instance |
BindingFlags.SetProperty,Type.DefaultBinder, c, args);
23 }
24 }
25 }
26
OK,一切OK。
不过有一点就是需要在每一个Form初始化的时候加上FormUtil的引用,可以说这也是一种装饰模式,保持了一个对Form的引用,但是面向对象的思想继承优先,而不是耦合优先,但是对于已经不能改动的代码这确实是最好的解决办法,如果是可以修改代码呢?抽象父类是否可以更好的解决呢?
这个问题就先放着吧。
已有的解决办法是通过反射实现的,效率可能存在一些问题,但是却是比较好的,因为这样不仅是Color,连别的属性都可以设置,只要再配置文件中做好了配置,并且在FormUtil加入相应的方法,都是可以的。
这确实是一个很不错的解决方案。