[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之中,
靈活度十分的廣大,希望這些介紹對大家有幫助 :)


