在这个系列的上篇中介绍了数据绑定语法的原理以及.NET中如何实现单向绑定,中篇我们简单的介绍了ASP.NET 2.0 中新增的Bind语法配合DataSourceControl来实现数据的自动双向绑定。这两部分的内容相对动态抽象并且不常接触,没有很好的源代码支持很难解释清楚,要想真正弄清它们的内部原理,还需要大家亲自动手去反编译分析动态编译的程序集。
在了解了数据绑定语法的原理后,我还想来谈谈我中实践过程中遇到的一些问题以及其它实用的绑定技巧。首先我们就来说说,特殊字段名的问题。我们知道在数据库当中,如果表名或字段名中包含有一些特殊的不能是合法的字符时,都会使用[]将它们引起来,以便他们能够正常使用。但是在<%# Eval("")%>的绑定语句当中,同时可以使用[],但是对于字段名中包含 "(",")","[","]"这4个字符却始终运行出错。假设像我下面这样来绑定"电压(V)":
<%# Eval("电压(V)")%>
那么就会得到一个运行时错误:
DataBinding:“System.Data.DataRowView”不包含名为“电压”的属性。
表明括号是被认为是一个特殊字符,那我们如果给字段名加上[],如下:
<%# Eval("[电压(V)]")%>
电压(V 既不是表 DataTable1 的 DataColumn 也不是 DataRelation。
表明,即使加上[]也无法解决这个特殊字段名的问题。同时字段名中如果也存在中括号,也是会出现这样的问题的。但是这样的字段名却在GridView的自动生成列中能被正常绑定呢?问题会出现在哪里呢?分析和对比GridView的自动生成列与Eval这样的绑定语法在最终执行绑定代码上的不同,我们可以发现,GridView的自动生成列取值并不是使用DataBinder.Eval这个方法,它内部有自己的取值方式,但是在实现上却是大同小异的。那究竟是在哪里出现了问题呢?我们找出DataBinder类的定义:
1: [AspNetHostingPermission(SecurityAction.LinkDemand, Level=200)]2: public sealed class DataBinder
3: {4: // Fields
5: private static readonly char[] expressionPartSeparator = new char[] { '.' };
6: private static readonly char[] indexExprEndChars = new char[] { ']', ')' };
7: private static readonly char[] indexExprStartChars = new char[] { '[', '(' };
8: 9: // Methods
10: public static object Eval(object container, string expression)
11: {12: if (expression == null)
13: {14: throw new ArgumentNullException("expression");
15: } 16: expression = expression.Trim();17: if (expression.Length == 0)
18: {19: throw new ArgumentNullException("expression");
20: }21: if (container == null)
22: {23: return null;
24: }25: string[] expressionParts = expression.Split(expressionPartSeparator);
26: return Eval(container, expressionParts);
27: } 28: 29: private static object Eval(object container, string[] expressionParts)
30: {31: object propertyValue = container;
32: for (int i = 0; (i < expressionParts.Length) && (propertyValue != null); i++)
33: {34: string propName = expressionParts[i];
35: if (propName.IndexOfAny(indexExprStartChars) < 0)
36: { 37: propertyValue = GetPropertyValue(propertyValue, propName); 38: }39: else
40: { 41: propertyValue = GetIndexedPropertyValue(propertyValue, propName); 42: } 43: }44: return propertyValue;
45: } 46: 47: public static string Eval(object container, string expression, string format)
48: {49: object obj2 = Eval(container, expression);
50: if ((obj2 == null) || (obj2 == DBNull.Value))
51: {52: return string.Empty;
53: }54: if (string.IsNullOrEmpty(format))
55: {56: return obj2.ToString();
57: }58: return string.Format(format, obj2);
59: } 60: 61: public static object GetDataItem(object container)
62: {63: bool flag;
64: return GetDataItem(container, out flag);
65: } 66: 67: public static object GetDataItem(object container, out bool foundDataItem)
68: {69: if (container == null)
70: {71: foundDataItem = false;
72: return null;
73: }74: IDataItemContainer container2 = container as IDataItemContainer;
75: if (container2 != null)
76: {77: foundDataItem = true;
78: return container2.DataItem;
79: }80: string name = "DataItem";
81: PropertyInfo property = container.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);82: if (property == null)
83: {84: foundDataItem = false;
85: return null;
86: }87: foundDataItem = true;
88: return property.GetValue(container, null);
89: } 90: 91: public static object GetIndexedPropertyValue(object container, string expr)
92: {93: if (container == null)
94: {95: throw new ArgumentNullException("container");
96: }97: if (string.IsNullOrEmpty(expr))
98: {99: throw new ArgumentNullException("expr");
100: }101: object obj2 = null;
102: bool flag = false;
103: int length = expr.IndexOfAny(indexExprStartChars);
104: int num2 = expr.IndexOfAny(indexExprEndChars, length + 1);
105: if (((length < 0) || (num2 < 0)) || (num2 == (length + 1)))
106: {107: throw new ArgumentException(SR.GetString("DataBinder_Invalid_Indexed_Expr", new object[] { expr }));
108: }109: string propName = null;
110: object obj3 = null;
111: string s = expr.Substring(length + 1, (num2 - length) - 1).Trim();
112: if (length != 0)
113: { 114: propName = expr.Substring(0, length); 115: }116: if<