[ASP.NET] 在Listview中動態更換Template

  • 12302
  • 0

[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之中,

靈活度十分的廣大,希望這些介紹對大家有幫助 :)

Dynamic Listview Template