模板化的数据绑定控件为我们在页面上显示数据提供了根本的灵活性你可能还记得ASPNET vx中的几个模板化控件(例如DataList和Repeater控件)ASPNET 仍然支持这些控件但在模板中绑定数据的语法已经被简化和改善了本文将讨论在数据绑定控件模板中绑定数据的多种方法
数据绑定表达式
ASPNET 改善了模板中的数据绑定操作把vx中的数据绑定语法DataBinderEval(ContainerDataItem fieldname)简化为Eval(fieldname)Eval方法与DataBinderEval一样可以接受一个可选的格式化字符串参数缩短的Eval语法与DataBinderEval的不同点在于Eval会根据最近的容器对象(例如DataListItem)的DataItem属性来自动地解析字段而DataBinderEval需要使用参数来指定容器由于这个原因Eval只能在数据绑定控件的模板中使用而不能用于Page(页面)层当然ASPNET 页面中仍然支持DataBinderEval你可以在不支持简化的Eval语法的环境中使用它
下面的例子演示了如何使用新的简化的Eval数据绑定语法绑定到DataList数据项模板(ItemTemplate)中的ImageLabel和HyperLink控件
<asp:DataList ID=DataList RepeatColumns= Width= runat=server DataSourceID=ObjectDataSource>
<ItemTemplate>
<asp:HyperLink ID=HyperLink runat=server NavigateUrl=<%# Eval(PhotoID PhotoFormViewPlainaspx?ID={}) %>>
<asp:Image ID=Image Runat=server ImageUrl=<%# Eval(FileName images/thumbs/{}) %> /></asp:HyperLink>
<asp:Label ID=CaptionLabel runat=server Text=<%# Eval(Caption) %> />
</ItemTemplate>
</asp:DataList><br />
<asp:ObjectDataSource ID=ObjectDataSource runat=server TypeName=DataComponentTableAdaptersPhotosTableAdapter SelectMethod=GetPhotosForAlbum>
数据绑定也可以作为控件的主题定义(theme definition)的一部分这样我们就可以通过改变主题来随意地改变模板化控件的布局和外观但是Theme(主题)模板中只能使用Eval(或者后面讨论的Bind)绑定到任意的用户代码是被禁止的
FormView控件
DataList控件在来自数据源的数据项中进行迭代操作并为每个数据项输出ItemTemplate(数据项模板)这对于显示数据项列表是有用的但是通常情况下你希望在一个窗体中实现单条数据项的绑定操作为了实现这个目的ASPNET 引入了FormView控件它能够在任意的模板中每次显示一个数据项DetailsView和FormView之间的主要差异在于DetailsView拥有内建的表格显示方式而FormView需要使用用户自定义的显示模板在其它方面FormView和DetailsView对象模型是非常相似的下面的例子显示了一个绑定到ObjectDataSource的FormView控件该FormView的ItemTemplate属性包含数据绑定的ImageLabel和HyperLink控件与前面的DataList示例类似
<asp:FormView ID=FormView runat=server DataSourceID=ObjectDataSource>
<ItemTemplate>
<asp:Label ID=CaptionLabel runat=server Text=<%# Eval(Caption) %> FontSize=pt /><br />
<asp:Image ID=Image runat=server ImageUrl=<%# Eval(FileName images/{}) %> />
<asp:HyperLink ID=HyperLink Text=Back to Album NavigateUrl=<%# Eval(AlbumID PhotosDataListaspx?ID={}) %> runat=server />
</ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID=ObjectDataSource runat=server TypeName=DataComponentTableAdaptersPhotosTableAdapter SelectMethod=GetPhoto>
<SelectParameters>
<asp:QueryStringParameter Name=PhotoID DefaultValue= QueryStringField=ID />
</SelectParameters>
</asp:ObjectDataSource>
FormView与DetailsView类似也跟蹤当前显示的数据项但是当数据源返回列表的时候我们也可以选择支持多个数据项的分页操作下面的例子显示了一个带有分页功能的FormView
<asp:FormView ID=FormView Runat=server DataSourceID=SqlDataSource
HeaderText=Books for Author AllowPaging=True>
<ItemTemplate>
<asp:Image ID=Image ImageUrl=<%# Eval(title_id~/Images/{}gif) %> Runat=server />
<asp:Label ID=Label FontSize=em FontBold=true Text=<%# Eval(title) %> runat=server />
<asp:Label ID=Label Text=<%# Eval(price{:c}) %> runat=server />
</ItemTemplate>
</asp:FormView>
<asp:SqlDataSource ID=SqlDataSource Runat=server SelectCommand=SELECT dboauthorsau_id dbotitlestitle_id dbotitlestitle dbotitlestype dbotitlesprice dbotitlesnotes FROM dboauthors INNER JOIN dbotitleauthor ON dboauthorsau_id = dbotitleauthorau_id INNER JOIN dbotitles ON dbotitleauthortitle_id = dbotitlestitle_id WHERE (dboauthorsau_id = @au_id)
ConnectionString=<%$ ConnectionStrings:Pubs %>>
<SelectParameters>
<asp:QueryStringParameter Name=au_id DefaultValue= QueryStringField=ID />
</SelectParameters>
</asp:SqlDataSource>
双向数据绑定
FormView可以通过相关的数据源控件支持自动地更新插入和删除操作(与DetailsView类似)如果要定义编辑或插入的UI那么除了定义数据项模板(ItemTemplate)之外你还要定义EditItemTemplate或InsertItemTemplate模板在这个模板中你可以把输入控件(例如文本框检查框或下拉列表)绑定到数据源的字段这些模板中的数据绑定使用了双向数据绑定语法允许FormView从模板的输入控件中提取值并传递给数据源这些数据绑定操作用新的Bind(fieldname)语法代替了Eval
请注意使用Bind语法的数据绑定控件必须设置好ID属性
GridView或DetailsView执行更新或插入操作的时候(这些控件的Columns或Fields都会定义BoundFields绑定字段)GridView或 DetailsView负责建立编辑或插入模式中的输入UI因此它能够自动地提取这些值并把它们传递给数据源由于模板包含了任意的用户自定义UI控件双向数据绑定语法就是必要的以确保模板化控件(例如FormView)在应对更新插入或删除操作的时候知道应该从模板中提取那些控件的值你仍然可以在EditItemTemplate中使用Eval语句进行数据绑定来给数据源传递值请注意FormView与DetailsView和GridView一样支持DataKeyNames属性它保存了传递给更新/删除操作的主键字典的原始值即使这些值没有显示出来
FormView支持DefaultMode属性它可以指定默认显示的模板但在默认情况下FormView处于只读模式并显示ItemTemplate模板为了把UI从只读模式转换为编辑或插入模式你可以给模板添加一个按钮控件把该按钮的CommandName属性设置为Edit或New在EditItemTemplate模板中你可以增加按钮把CommandName设置为Update或Cancel以提交或终止更新操作类似的你可以增加按钮把CommandName设置为Insert或Cancel来提交或终止插入操作
下面的例子演示了定义了ItemTemplate和EditItemTemplate模板的FormView其中的ItemTemplate模板包含了使用Eval(双向)绑定的控件而EditItemTemplate模板则包含了使用Bind语句进行双向绑定的文本框控件主键字段(PhotoID)是使用DataKeyNames属性存放在viewstate中的该FormView包含了用于在模板之间进行切换的按钮
<asp:FormView ID=FormView runat=server DataSourceID=ObjectDataSource DataKeyNames=PhotoID>
<EditItemTemplate>
<b>Enter a New Caption:</b>
<asp:TextBox Text=<%# Bind(Caption) %> runat=server ID=CaptionTextBox /><asp:Button ID=Button runat=server Text=Update CommandName=Update />
<asp:Button ID=Button runat=server Text=Cancel CommandName=Cancel />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID=CaptionLabel runat=server Text=<%# Eval(Caption) %> FontSize=pt /><br />
<asp:Image ID=Image runat=server ImageUrl=<%# Eval(FileName images/{}) %> /> <br />
<asp:Button ID=Button runat=server Text=Edit Caption CommandName=Edit /> <asp:HyperLink ID=HyperLink Text=Back to Album NavigateUrl=<%# Eval(AlbumID PhotosDataListaspx?ID={}) %> runat=server />
</ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID=ObjectDataSource runat=server TypeName=DataComponentTableAdaptersPhotosTableAdapter SelectMethod=GetPhoto UpdateMethod=UpdateCaption OldValuesParameterFormatString=original_{}>
<UpdateParameters>
<asp:Parameter Name=Caption />
<asp:Parameter Name=Original_PhotoID />
</UpdateParameters>
<SelectParameters>
<asp:QueryStringParameter Name=PhotoID DefaultValue= QueryStringField=ID />
</SelectParameters>
</asp:ObjectDataSource>
GridView和DetailsView还支持模板化UI它是通过给Columns或Fields集合增加TemplateField来实现的TemplateField支持使用ItemTemplateEditItemTemplate和InsertItemTemplate(DetailsView才有)为控件的不同显示模式中的字段指定UI与上面的FormView示例类似EditItemTemplate或InsertItemTemplate中的双向数据绑定也允许GridView或DetailsView从这些模板的控件中提取值TemplateField最常见的用途是给EditItemTemplate增加验证器控件用于公开地验证GridView或DetailsView操作下面的例子演示了这种技术
……
<asp:GridView ID=GridView runat=server DataSourceID=ObjectDataSource AutoGenerateColumns=False AllowPaging=True AllowSorting=True DataKeyNames=AlbumID>
<Columns>
<asp:CommandField ShowEditButton=True />
<asp:BoundField ReadOnly=True HeaderText=AlbumID DataField=AlbumID SortExpression=AlbumID />
<asp:TemplateField HeaderText=AlbumName SortExpression=AlbumName ItemStyleWrap=false>
<ItemTemplate>
<asp:Label ID=Label runat=server Text=<%# Eval(AlbumName) %>></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID=TextBox runat=server Text=<%# Bind(AlbumName) %>></asp:TextBox>
<asp:RequiredFieldValidator ControlToValidate=TextBox ErrorMessage=AlbumName cannot be empty ID=RequiredFieldValidator Display=Dynamic runat=server>*</asp:RequiredFieldValidator>
</EditItemTemplate>
</asp:TemplateField>
……
</asp:GridView><br />
<asp:ValidationSummary ID=ValidationSummary runat=server />
<asp:ObjectDataSource ID=ObjectDataSource runat=server ConvertNullToDBNull=true
TypeName=DataComponentTableAdaptersAlbumsTableAdapter SelectMethod=GetAlbumsByOwner UpdateMethod=Update OldValuesParameterFormatString=original_{}>
……
</asp:ObjectDataSource>
TemplateField的另外一种用途是定制给GridView或DetailsView列/字段输入值的控件例如你可以在TemplateField的EditItemTemplate中放置一个DropDownList允许用户从预定义的值列表中选择下面的例子演示了这种技术请注意示例中的下拉列表绑定到了自己的数据源控件以动态地获取列表值
<asp:TemplateField HeaderText=Owner SortExpression=Owner>
<ItemTemplate>
<asp:Label ID=Label runat=server Text=<%# Eval(Owner) %>></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList DataSourceID=ObjectDataSource DataTextField=Owner DataValueField=Owner ID=DropDownList runat=server SelectedValue=<%# Bind(Owner) %>>
</asp:DropDownList>
</EditItemTemplate>
<ItemStyle Wrap=False />
</asp:TemplateField>