|
在ASP.NET我們?cè)谑褂肦epeater,DetailsView,F(xiàn)ormView,GridView等數(shù)據(jù)綁定模板時(shí),都會(huì)使用<%# Eval("字段名") %>或<%# Bind("字段名") %>這樣的語(yǔ)法來(lái)單向或雙向綁定數(shù)據(jù)。但是我們卻很少去了解,在這些語(yǔ)法的背后,ASP.NET究竟都做了哪些事情來(lái)方便我們使用這樣的語(yǔ)法來(lái)綁定數(shù)據(jù)。究竟解析這樣的語(yǔ)法是在編譯時(shí),還是運(yùn)行時(shí)?如果沒(méi)有深入去了解,我們肯定不得而知。這個(gè)簡(jiǎn)短的系列文章就是帶我們大家一起去深入探究一下ASP.NET綁定語(yǔ)法的內(nèi)部機(jī)理,以讓我們更加全面的認(rèn)識(shí)和運(yùn)用它。
事件的起因是,我希望動(dòng)態(tài)的為Repeater控件添加行項(xiàng)模板,我可以通過(guò)實(shí)現(xiàn)ITempate接口的方式來(lái)動(dòng)態(tài)添加行模板。并希望它通過(guò)普通的頁(yè)面綁定語(yǔ)法來(lái)完成數(shù)據(jù)字段的綁定功能,如下就是一個(gè)簡(jiǎn)單的例子:
/// <summary>
/// Summary description for DynamicTemplate
/// </summary>
public class DynamicTemplate : ITemplate
{
public DynamicTemplate()
{
//
// TODO: Add constructor logic here
//
}
#region ITemplate Members
public void InstantiateIn(Control container)
{
TextBox textBox = new TextBox();
textBox.Text = @"<%# Eval(""ID"") %>";
container.Controls.Add(textBox);
}
#endregion
}在.NET 2.0中新增了雙向的數(shù)據(jù)綁定方式,主要用在GridView,DetailsView,FormView等數(shù)據(jù)容器控件中,結(jié)合DataSourceControl就可以非常輕松的完成數(shù)據(jù)的更新和提交工作,而不需要我們手工去遍歷輸入控件的值。那在這樣的雙向數(shù)據(jù)綁定中,ASP.NET又是做了哪些工作,來(lái)為我們透明輸入控件與字段的取值與對(duì)應(yīng)關(guān)系,讓我們可以在DataSouceControl中方便得到數(shù)據(jù)項(xiàng)修改前的值和修改后的值?下面就讓我們一起來(lái)從一段頁(yè)面代碼開(kāi)始吧:
<ASP:DetailsDataSouce ID="DetailsDataSouce1" runat="server">
</ASP:DetailsDataSouce>
<ASP:DetailsView ID="detailsView" runat="server" DefaultMode="Edit" DataSourceID="DetailsDataSouce1">
<Fields>
<ASP:TemplateField>
<HeaderTemplate>
電流:</HeaderTemplate>
<EditItemTemplate>
<ASP:TextBox ID="textBox1" runat="server" Text='<%# Bind("[電流{a}]")%>'></ASP:TextBox>
</EditItemTemplate>
</ASP:TemplateField>
</Fields>
</ASP:DetailsView>在了解了數(shù)據(jù)綁定語(yǔ)法的原理后,我還想來(lái)談?wù)勎抑袑?shí)踐過(guò)程中遇到的一些問(wèn)題以及其它實(shí)用的綁定技巧。首先我們就來(lái)說(shuō)說(shuō),特殊字段名的問(wèn)題。我們知道在數(shù)據(jù)庫(kù)當(dāng)中,如果表名或字段名中包含有一些特殊的不能是合法的字符時(shí),都會(huì)使用[]將它們引起來(lái),以便他們能夠正常使用。但是在<%# Eval("")%>的綁定語(yǔ)句當(dāng)中,同時(shí)可以使用[],但是對(duì)于字段名中包含"(",")","[","]"這4個(gè)字符卻始終運(yùn)行出錯(cuò)。假設(shè)像我下面這樣來(lái)綁定"電壓(V)":<%# Eval("[電壓(V)]")%>
那么就會(huì)得到一個(gè)運(yùn)行時(shí)錯(cuò)誤:
DataBinding:“System.Data.DataRowView”不包含名為“電壓”的屬性。
表明括號(hào)是被認(rèn)為是一個(gè)特殊字符,那我們?nèi)绻o字段名加上[],如下:<%# Eval("[電壓(V)]")%>
此時(shí),我們會(huì)得到另一個(gè)運(yùn)行時(shí)錯(cuò)誤:
電壓(V 既不是表 DataTable1 的 DataColumn 也不是 DataRelation。
表明,即使加上[]也無(wú)法解決這個(gè)特殊字段名的問(wèn)題。同時(shí)字段名中如果也存在中括號(hào),也是會(huì)出現(xiàn)這樣的問(wèn)題的。但是這樣的字段名卻在GridView的自動(dòng)生成列中能被正常綁定呢?問(wèn)題會(huì)出現(xiàn)在哪里呢?分析和對(duì)比GridView的自動(dòng)生成列與Eval這樣的綁定語(yǔ)法在最終執(zhí)行綁定代碼上的不同,我們可以發(fā)現(xiàn),GridView的自動(dòng)生成列取值并不是使用DataBinder.Eval這個(gè)方法,它內(nèi)部有自己的取值方式,但是在實(shí)現(xiàn)上卻是大同小異的。那究竟是在哪里出現(xiàn)了問(wèn)題呢?我們找出DataBinder類(lèi)的定義:
代碼
[ASPNETHostingPermission(SecurityAction.LinkDemand, Level=200)]
public sealed class DataBinder
{
// Fields
private static readonly char[] expressionPartSeparator = new char[] { '.' };
private static readonly char[] indexExprEndChars = new char[] { ']', ')' };
private static readonly char[] indexExprStartChars = new char[] { '[', '(' };
// Methods
public static object Eval(object container, string expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
expression = expression.Trim();
if (expression.Length == 0)
{
throw new ArgumentNullException("expression");
}
if (container == null)
{
return null;
}
string[] expressionParts = expression.Split(expressionPartSeparator);
return Eval(container, expressionParts);
}
private static object Eval(object container, string[] expressionParts)
{
object propertyValue = container;
for (int i = 0; (i < expressionParts.Length)&& (propertyValue != null); i++)
{
string propName = expressionParts[i];
if (propName.IndexOfAny(indexExprStartChars)< 0)
{
propertyValue = GetPropertyValue(propertyValue, propName);
}
else
{
propertyValue = GetIndexedPropertyValue(propertyValue, propName);
}
}
return propertyValue;
}
public static string Eval(object container, string expression, string format)
{
object obj2 = Eval(container, expression);
if ((obj2 == null)||(obj2 == DBNull.Value))
{
return string.Empty;
}
if (string.IsNullOrEmpty(format))
{
return obj2.ToString();
}
return string.Format(format, obj2);
}
public static object GetDataItem(object container)
{
bool flag;
return GetDataItem(container, out flag);
}
public static object GetDataItem(object container, out bool foundDataItem)
{
if (container == null)
{
foundDataItem = false;
return null;
}
IDataItemContainer container2 = container as IDataItemContainer;
if (container2 != null)
{
foundDataItem = true;
return container2.DataItem;
}
string name = "DataItem";
PropertyInfo property = container.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (property == null)
{
foundDataItem = false;
return null;
}
foundDataItem = true;
return property.GetValue(container, null);
}
public static object GetIndexedPropertyValue(object container, string expr)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
if (string.IsNullOrEmpty(expr))
{
throw new ArgumentNullException("expr");
}
object obj2 = null;
bool flag = false;
int length = expr.IndexOfAny(indexExprStartChars);
int num2 = expr.IndexOfAny(indexExprEndChars, length + 1);
if (((length < 0)||(num2 < 0))||(num2 == (length + 1)))
{
throw new ArgumentException(SR.GetString("DataBinder_Invalid_Indexed_Expr", new object[] { expr }));
}
string propName = null;
object obj3 = null;
111: string s = expr.Substring(length + 1,(num2 - length)- 1).Trim();
if (length != 0)
{
propName = expr.Substring(0, length);
}
if (s.Length != 0)
{
if (((s[0] == '"')&& (s[s.Length - 1] == '"'))||((s[0] == '/'')&& (s[s.Length - 1] == '/'')))
{
obj3 = s.Substring(1, s.Length - 2);
}
else if (char.IsDigit(s[0]))
{
int num3;
flag = int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out num3);
if (flag)
{
obj3 = num3;
}
else
{
obj3 = s;
}
}
else
{
obj3 = s;
}
}
if (obj3 == null)
{
throw new ArgumentException(SR.GetString("DataBinder_Invalid_Indexed_Expr", new object[] { expr }));
}
object propertyValue = null;
if ((propName != null)&& (propName.Length != 0))
{
propertyValue = GetPropertyValue(container, propName);
}
else
{
propertyValue = container;
}
if (propertyValue == null)
{
return obj2;
}
Array array = propertyValue as Array;
if ((array!= null)&& flag)
{
return array.GetValue((int) obj3);
}
if ((propertyValue is IList)&& flag)
{
return ((IList) propertyValue)[(int) obj3];
}
PropertyInfo info = propertyValue.GetType().GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, null, new Type[] { obj3.GetType()}, null);
if (info == null)
{
throw new ArgumentException(SR.GetString("DataBinder_No_Indexed_Accessor", new object[] { propertyValue.GetType().FullName }));
}
return info.GetValue(propertyValue, new object[] { obj3 });
}
public static string GetIndexedPropertyValue(object container, string propName, string format)
{
object indexedPropertyValue = GetIndexedPropertyValue(container, propName);
if ((indexedPropertyValue == null)||(indexedPropertyValue == DBNull.Value))
{
return string.Empty;
}
if (string.IsNullOrEmpty(format))
{
return indexedPropertyValue.ToString();
}
return string.Format(format, indexedPropertyValue);
}
public static object GetPropertyValue(object container, string propName)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
if (string.IsNullOrEmpty(propName))
{
throw new ArgumentNullException("propName");
}
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(container).Find(propName, true);
if (descriptor == null)
{
throw new HttpException(SR.GetString("DataBinder_Prop_Not_Found", new object[] { container.GetType().FullName, propName }));
}
return descriptor.GetValue(container);
}
public static string GetPropertyValue(object container, string propName, string format)
{
object propertyValue = GetPropertyValue(container, propName);
if ((propertyValue == null)||(propertyValue == DBNull.Value))
{
return string.Empty;
}
if (string.IsNullOrEmpty(format))
{
return propertyValue.ToString();
}
return string.Format(format, propertyValue);
}
internal static bool IsNull(object value)
{
if ((value != null)&& !Convert.IsDBNull(value))
{
return false;
}
return true;
}
}
NET技術(shù):深入ASP.NET數(shù)據(jù)綁定,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。