模板化的資料繫結控制項為我們在頁面上顯示資料提供了根本的靈活性。你可能還記得ASP.NET v1.x中的幾個樣板化控制項(例如DataList和Repeater控制項)。ASP.NET 2.0仍然支援這些控制項,但在模板中綁定資料的文法已經被簡化和改善了。本文將討論在資料繫結控制項模板中綁定資料的多種方法。 資料繫結運算式 ASP.NET 2.0改善了模板中的資料繫結操作,把v1.x中的資料繫結文法DataBinder.Eval(Container.DataItem, fieldname)簡化為Eval(fieldname)。Eval方法與DataBinder.Eval一樣可以接受一個可選的格式化字串參數。縮短的Eval文法與DataBinder.Eval的不同點在於,Eval會根據最近的容器物件(例如DataListItem)的DataItem屬性來自動地解析欄位,而DataBinder.Eval需要使用參數來指定容器。由於這個原因,Eval只能在資料繫結控制項的模板中使用,而不能用於Page(頁面)層。當然,ASP.NET 2.0頁面中仍然支援DataBinder.Eval,你可以在不支援簡化的Eval文法的環境中使用它。 下面的例子示範了如何使用新的簡化的Eval資料繫結文法綁定到DataList資料項目模板(ItemTemplate)中的Image、Label和HyperLink控制項。 <asp:DataList ID="DataList1" RepeatColumns="5" Width="600" runat="server" DataSourceID="ObjectDataSource1"> <ItemTemplate> <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl=''<%# Eval("PhotoID", "PhotoFormViewPlain.aspx?ID={0}") %>''> <asp:Image ID="Image1" Runat="server" ImageUrl=''<%# Eval("FileName", "images/thumbs/{0}") %>'' /></asp:HyperLink> <asp:Label ID="CaptionLabel" runat="server" Text=''<%# Eval("Caption") %>'' /> </ItemTemplate> </asp:DataList><br /> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataComponentTableAdapters.PhotosTableAdapter" SelectMethod="GetPhotosForAlbum"> 資料繫結也可以作為控制項的主題定義(theme definition)的一部分,這樣我們就可以通過改變主題來隨意地改變樣板化控制項的布局和外觀。但是Theme(主題)模板中只能使用Eval(或者後面討論的Bind)。綁定到任意的使用者代碼是被禁止的。 FormView控制項 DataList控制項在來自資料來源的資料項目中進行迭代操作,並為每個資料項目輸出ItemTemplate(資料項目模板)。這對於顯示資料項目列表是有用的,但是通常情況下,你希望在一個表單中實現單條資料項目的綁定操作。為了實現這個目的,ASP.NET 2.0引入了FormView控制項,它能夠在任意的模板中每次顯示一個資料項目。DetailsView和FormView之間的主要差異在於,DetailsView擁有內建的表格顯示方式,而FormView需要使用使用者自訂的顯示模板。在其它方面FormView和DetailsView物件模型是非常相似的。下面的例子顯示了一個綁定到ObjectDataSource的FormView控制項。該FormView的ItemTemplate屬性包含資料繫結的Image、Label和HyperLink控制項,與前面的DataList樣本類似。 <asp:FormView ID="FormView1" runat="server" DataSourceID="ObjectDataSource1"> <ItemTemplate> <asp:Label ID="CaptionLabel" runat="server" Text=''<%# Eval("Caption") %>'' Font-Size="32pt" /><br /> <asp:Image ID="Image1" runat="server" ImageUrl=''<%# Eval("FileName", "images/{0}") %>'' /> <asp:HyperLink ID="HyperLink1" Text="Back to Album" NavigateUrl=''<%# Eval("AlbumID", "PhotosDataList.aspx?ID={0}") %>'' runat="server" /> </ItemTemplate> </asp:FormView> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataComponentTableAdapters.PhotosTableAdapter" SelectMethod="GetPhoto"> <SelectParameters> <asp:QueryStringParameter Name="PhotoID" DefaultValue="9" QueryStringField="ID" /> </SelectParameters> </asp:ObjectDataSource> FormView與DetailsView類似,也跟蹤當前顯示的資料項目,但是當資料來源返回列表的時候,我們也可以選擇支援多個資料項目的分頁操作。下面的例子顯示了一個帶有分頁功能的FormView。 <asp:FormView ID="FormView1" Runat="server" DataSourceID="SqlDataSource1" HeaderText="Books for Author" AllowPaging="True"> <ItemTemplate> <asp:Image ID="Image1" ImageUrl=''<%# Eval("title_id","~/Images/{0}.gif") %>'' Runat="server" /> <asp:Label ID="Label1" Font-Size="1.2em" Font-Bold="true" Text=''<%# Eval("title") %>'' runat="server" /> <asp:Label ID="Label2" Text=''<%# Eval("price","{0:c}") %>'' runat="server" /> </ItemTemplate> </asp:FormView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT dbo.authors.au_id, dbo.titles.title_id, dbo.titles.title, dbo.titles.type, dbo.titles.price, dbo.titles.notes FROM dbo.authors INNER JOIN dbo.titleauthor ON dbo.authors.au_id = dbo.titleauthor.au_id INNER JOIN dbo.titles ON dbo.titleauthor.title_id = dbo.titles.title_id WHERE (dbo.authors.au_id = @au_id)" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:QueryStringParameter Name="au_id" DefaultValue="213-46-8915" 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="FormView1" runat="server" DataSourceID="ObjectDataSource1" DataKeyNames="PhotoID"> <EditItemTemplate> <b>Enter a New Caption:</b> <asp:TextBox Text=''<%# Bind("Caption") %>'' runat="server" ID="CaptionTextBox" /> <asp:Button ID="Button1" runat="server" Text="Update" CommandName="Update" /> <asp:Button ID="Button2" runat="server" Text="Cancel" CommandName="Cancel" /> </EditItemTemplate> <ItemTemplate> <asp:Label ID="CaptionLabel" runat="server" Text=''<%# Eval("Caption") %>'' Font-Size="32pt" /><br /> <asp:Image ID="Image1" runat="server" ImageUrl=''<%# Eval("FileName", "images/{0}") %>'' /> <br /> <asp:Button ID="Button3" runat="server" Text="Edit Caption..." CommandName="Edit" /> <asp:HyperLink ID="HyperLink1" Text="Back to Album" NavigateUrl=''<%# Eval("AlbumID", "PhotosDataList.aspx?ID={0}") %>'' runat="server" /> </ItemTemplate> </asp:FormView> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataComponentTableAdapters.PhotosTableAdapter" SelectMethod="GetPhoto" UpdateMethod="UpdateCaption" OldValuesParameterFormatString="original_{0}"> <UpdateParameters> <asp:Parameter Name="Caption" /> <asp:Parameter Name="Original_PhotoID" /> </UpdateParameters> <SelectParameters> <asp:QueryStringParameter Name="PhotoID" DefaultValue="9" QueryStringField="ID" /> </SelectParameters> </asp:ObjectDataSource> GridView和DetailsView還支援模板化UI,它是通過給Columns或Fields集合增加TemplateField來實現的。TemplateField支援使用ItemTemplate、EditItemTemplate和InsertItemTemplate(DetailsView才有)為控制項的不同顯示模式中的欄位指定UI。與上面的FormView樣本類似,EditItemTemplate或InsertItemTemplate中的雙向資料繫結也允許GridView或DetailsView從這些模板的控制項中提取值。TemplateField最常見的用途是給EditItemTemplate增加驗證器控制項,用於公開地驗證GridView或DetailsView操作。下面的例子示範了這種技術。 …… <asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1" 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" ItemStyle-Wrap="false"> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text=''<%# Eval("AlbumName") %>''></asp:Label> </ItemTemplate> <EditItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Text=''<%# Bind("AlbumName") %>''></asp:TextBox> <asp:RequiredFieldValidator ControlToValidate="TextBox1" ErrorMessage="AlbumName cannot be empty" ID="RequiredFieldValidator1" Display="Dynamic" runat="server">*</asp:RequiredFieldValidator> </EditItemTemplate> </asp:TemplateField> …… </asp:GridView><br /> <asp:ValidationSummary ID="ValidationSummary1" runat="server" /> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" ConvertNullToDBNull="true" TypeName="DataComponentTableAdapters.AlbumsTableAdapter" SelectMethod="GetAlbumsByOwner" UpdateMethod="Update" OldValuesParameterFormatString="original_{0}"> …… </asp:ObjectDataSource> TemplateField的另外一種用途是定製給GridView或DetailsView列/欄位輸入值的控制項。例如,你可以在TemplateField的EditItemTemplate中放置一個DropDownList,允許使用者從預定義的值列表中選擇。下面的例子示範了這種技術。請注意,樣本中的下拉式清單綁定到了自己的資料來源控制項,以動態地擷取列表值。 <asp:TemplateField HeaderText="Owner" SortExpression="Owner"> <ItemTemplate> <asp:Label ID="Label2" runat="server" Text=''<%# Eval("Owner") %>''></asp:Label> </ItemTemplate> <EditItemTemplate> <asp:DropDownList DataSourceID="ObjectDataSource2" DataTextField="Owner" DataValueField="Owner" ID="DropDownList2" runat="server" SelectedValue=''<%# Bind("Owner") %>''> </asp:DropDownList> </EditItemTemplate> <ItemStyle Wrap="False" /> </asp:TemplateField> |