[ASP.NET] 在Listview中動態更換Template
自從在.Net Framework 3.5出現Listview之後,一直為它的靈活性所深深吸引,
最近在專案之中剛好有需求是必須依照不同的使用者,動態的更換UI的呈現,
所以就研究了一下如何在ASP.NET中動態更換Listview的Template
首先,我們一樣先建立一個Listview,資料則使用Northwind資料庫的Products Table
如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Dynamic change listview template sample</title>
<link href="TableStyle.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList_TemplateType" runat="server" OnSelectedIndexChanged="DropDownList_TemplateType_SelectedIndexChanged"
AutoPostBack="true">
<asp:ListItem Text="Template 1" />
<asp:ListItem Text="Template 2" />
<asp:ListItem Text="Template 3" />
</asp:DropDownList>
<asp:ListView ID="Listview_Products" runat="server">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
</ItemTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
在頁面中,我們可以看到一個DropDownList,它提供三個選項供使用者替換樣版,
在選項改變時觸發OnSelectedIndexChanged事件,Postback更換目前所選擇的樣板。
而在ItemTempalte中,目前並沒有任何的東西,
因為我們將在Code Behind中,直接動態的讀入我們已經建立好的樣板 ,
如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
setTemplate(DropDownList_TemplateType.SelectedIndex);
}
}
protected void DropDownList_TemplateType_SelectedIndexChanged(object sender, EventArgs e)
{
setTemplate(DropDownList_TemplateType.SelectedIndex);
}
private void setTemplate(int selectIndex)
{
//Get Template By index
ITemplate listviewTemplate = getTemplateByIndex(selectIndex);
//Create Datasource
NorthWindDataContext dataContext = new NorthWindDataContext();
var result = from d in dataContext.Products
select d;
//Binding Data
Listview_Products.ItemTemplate = listviewTemplate;
Listview_Products.DataSource = result;
Listview_Products.DataBind();
}
private ITemplate getTemplateByIndex(int selectIndex)
{
ITemplate listviewTemplate;
switch (selectIndex + 1)
{
case 1:
case 2:
listviewTemplate = LoadTemplate("~/ProductTemplate_" + (selectIndex + 1).ToString() + ".ascx");
break;
case 3:
default:
listviewTemplate = new ProjectTemplage_3();
break;
}
return listviewTemplate;
}
}
在程式碼中我們可以看到,當OnSelectedIndexChanged事件觸發時,
我們會將DropDownList.SelectedValue當做Key傳入getTemplateByIndex方法中,
動態的取得樣版,並將其指定到Listview中,而在此處我們可以看到,
動態載入樣版的方法共有兩種,
一種是使用LoadTemplate Method載入我們定義在UserControl中的樣板,
另外一種則是使用Template Class在Code中動態產生樣板,
我們先來看看在UserControl中所建立的樣板,如下
ProductTemplate_1.ascx
<%@ Control Language="C#" %>
<table class="table1">
<tr>
<th>
ID:
</th>
<td>
<%#Eval("ProductID") %>
</td>
</tr>
<tr>
<th>
ProductName:
</th>
<td>
<%#Eval("ProductName") %>
</td>
</tr>
<tr>
<th>
UnitPrice:
</th>
<td>
<%#Eval("UnitPrice") %>
</td>
</tr>
</table>
ProductTemplate_2.ascx
<%@ Control Language="C#" %>
<table class="table2">
<tr>
<th>
ID:
</th>
<td>
<%#Eval("ProductID") %>
</td>
</tr>
<tr>
<th>
ProductName:
</th>
<td>
<%#Eval("ProductName") %>
</td>
</tr>
<tr>
<th>
UnitPrice:
</th>
<td>
<%#Eval("UnitPrice") %>
</td>
</tr>
<tr>
<th>
ReOrderLevel:
</th>
<td>
<%#Eval("ReOrderLevel") %>
</td>
</tr>
</table>
從以上我們可以看到,其實跟一般我們在Itemplate中所建立的樣板,幾乎是一模一樣的,
只是現在我們把它抽出來放到User Control之中,就可以達到動態抽換樣版的目的了,
是不是十分簡單呢?
再來我們看看如何使用Class的方式來建立樣版,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
public class ProjectTemplage_3 : ITemplate
{
public void InstantiateIn(Control container)
{
//Create Table
Table table = new Table() { CssClass = "table3" };
for (int i = 0; i < 3; i++)
{
TableRow row = new TableRow();
TableCell cellTitle = new TableCell();
TableCell cellValue = new TableCell();
row.Cells.Add(cellTitle);
row.Cells.Add(cellValue);
table.Rows.Add(row);
}
//Create Label
Label label_ProductID = new Label() { ID = "Label_ProductID" };
Label label_ProductName = new Label() { ID = "Label_ProductName" };
Label label_UnitPrice = new Label() { ID = "Label_UnitPrice" };
//Insert default title and labels
table.Rows[0].Cells[0].Text = "ProductID:";
table.Rows[1].Cells[0].Text = "ProductName:";
table.Rows[2].Cells[0].Text = "UnitPrice:";
table.Rows[0].Cells[1].Controls.Add(label_ProductID);
table.Rows[1].Cells[1].Controls.Add(label_ProductName);
table.Rows[2].Cells[1].Controls.Add(label_UnitPrice);
//Delegate Databinding event
table.DataBinding +=new EventHandler(table_DataBinding);
//Add Control to container
container.Controls.Add(table);
}
private void table_DataBinding(object sender, EventArgs e)
{
//Get Table from sender
Table container = sender as Table;
//Get Dataitem
Product dataitem = ((IDataItemContainer)container.NamingContainer).DataItem as Product;
//Binding Data
(container.FindControl("Label_ProductID") as Label).Text = dataitem.ProductID.ToString();
(container.FindControl("Label_ProductName") as Label).Text = dataitem.ProductName;
(container.FindControl("Label_UnitPrice") as Label).Text = dataitem.UnitPrice.ToString();
}
}
在此處我們必須讓Class繼承Itemplate Interface,
而在InstantiateIn function中,我們動態的新增了一個 3 x 2的 Table,
並加入三個Label,來存放將要綁定的資料,
並且我們替table註冊了DataBinding的事件,來動態的替樣版綁上資料
(在table_Databinding事件中,特別值得注意的是在第二行中,
我們將container.NamingContainer轉換成為一個IDataItemContainer的基底介面,
其實在Listview中,此處的container.NamingContainer應該是ListviewDataItem,
但我們使用一個基底介面來增加使用上的彈性)
動態更換Listview的樣板,除了依照使用者不同呈現不同的資料之外,
還有許許多多的可能性可以利用,同樣的這種觀念也可以應用在UpdatePanel之中,
靈活度十分的廣大,希望這些介紹對大家有幫助 :)