VS2003中,datagrid非模板列能正常编辑及更新,但改为模板列后,能进入编辑状态,点击 "更新 ",出现错误:
无法将类型为“System.Web.UI.LiteralControl”的对象强制转换为类型“System.Web.UI.WebControls.TextBox”。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.InvalidCastException: 无法将类型为“System.Web.UI.LiteralControl”的对象强制转换为类型“System.Web.UI.WebControls.TextBox”。
源错误:
行 321: tb = CType(e.Item.Cells(4).Controls(0), TextBox)
行 322: type4 = tb.Text
行 323: tb = CType(e.Item.Cells(7).Controls(0), TextBox) '出现错误
行 324: jieguo7 = tb.Text
行 325: tb = CType(e.Item.Cells(8).Controls(0), TextBox)
------解决方案--------------------------------------------------------
使用 e.Item.FindControl(...) 定位控件。
Cells里边是完全可能改变的。例如写:
yourDataGrid.Items[4].Cells[4].Attributes[ "colspan "]= "2 ";
yourDataGrid.Items[4].Cells.RemoveAt(5);
这就合并了第5行中第5、6单元格。所以,使用“Cells[整数]”这种方法,对于个人开发软件来说就是给自己设置易出错的圈套,对于团队开发软件来说就是太想当然。
------解决方案--------------------------------------------------------
e.Item.Cells(8).FindControl( "你的文本框控件名 ")
------解决方案--------------------------------------------------------
假设模板中的TextBox的id是abc,写:
tb = CType(e.Item.FindControl( "abc "), TextBox)
------解决方案--------------------------------------------------------
e.Item.FindControl( "abc ")
e.Item.Cells(0).FindControl( "abc ")
e.Item.Cells(8).FindControl( "abc ")
毫无分别,全都返回同一个控件。
可以自己试一下,不论你要找的id为abc的控件在哪一列,Cells(n)这里的n可以随便胡写,只要缺失有n+1列,都能找到abc控件。
实际上,这说明写Cells(n)貌似正确(abc确实在某一个列中,因此很自然想到可以从这个列开始FindControl),实际上不一定正确(因为你实际上可以随便写这个n)。正确的是从行查找,而不是从单元格查找。实际上,当你从单元格查找的时候,asp.net会先找它所在行,然后从行开始查找,所以会有这个结果。
------解决方案--------------------------------------------------------
在说得技术明确一点,Control.FindControl(...) 中的这个 Control 应该是实现了 INamingContainer接口的控件。如果没有实现,asp.net就先向上查找 parent,直到找到实现这个接口的控件,才开始查找控件。
但是这个做法应该是用来兼容业余或者不成熟的写法的。上面已经说个,这容易“貌似正确”。
如果你技术比较好,那么你写这类代码的时候都要注意仅对具有 INamingContainer 的控件执行 FindControl 操作,这样的代码比较成文自明。