ASP.NET `TreeView` 控制項支援靜態定義節點,也可透過 `XmlDataSource`、`SiteMapDataSource` 繫結資料,但不直接支援 `SqlDataSource`。本文示範如何從資料庫動態載入節點,並利用 `PopulateOnDemand` 實現延遲載入,最後搭配 `
| 屬性/事件 | 說明 |
|---|---|
| TreeNode.SelectAction | 節點被選取時的行為:`Select`(觸發 `SelectedNodeChanged`)、`Expand`、`SelectExpand`、或導航模式(設定 `NavigateUrl`)。 |
| TreeNode.PopulateOnDemand | 設為 `true` 時,節點展開時才透過回發動態載入子節點,需處理 `TreeNodePopulate` 事件。 |
| TreeView.TreeNodePopulate | 當 `PopulateOnDemand=true` 的節點被展開時觸發,在此事件中以程式碼填充子節點。 |
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace DBHelper
{
public class DALHelper
{
private static string constr = ConfigurationManager.ConnectionStrings["MyNBAData"].ConnectionString;
private static SqlConnection connection = new SqlConnection(constr);
public static bool CheckConnOpen()
{
if (connection == null || connection.State == ConnectionState.Closed)
{ connection.Open(); return true; }
return false;
}
public static bool CheckConnClosed()
{
if (connection != null && connection.State == ConnectionState.Open)
{ connection.Close(); return true; }
return false;
}
public static DataTable GetDataTable(string sql)
{
using (SqlDataAdapter da = new SqlDataAdapter(sql, connection))
{
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
public static SqlDataReader ExecuteReader(string sql, SqlParameter[] parms)
{
using (SqlCommand cmd = new SqlCommand(sql, connection))
{
if (parms != null) foreach (var p in parms) cmd.Parameters.Add(p);
CheckConnOpen();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
}
public static int ExecuteNonQuery(string sql, SqlParameter[] parms)
{
using (SqlCommand cmd = new SqlCommand(sql, connection))
{
if (parms != null) foreach (var p in parms) cmd.Parameters.Add(p);
CheckConnOpen();
int count = cmd.ExecuteNonQuery();
CheckConnClosed();
return count;
}
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TreeNode root = new TreeNode("產品分類", "0");
root.PopulateOnDemand = true; // 開啟動態載入
TreeView1.Nodes.Add(root);
}
}
protected void TreeView1_TreeNodePopulate(object sender, TreeNodeEventArgs e)
{
string parentId = e.Node.Value;
DataTable dt = DALHelper.GetDataTable($"SELECT Id, Name FROM Categories WHERE ParentId = {parentId}");
foreach (DataRow row in dt.Rows)
{
TreeNode child = new TreeNode(row["Name"].ToString(), row["Id"].ToString());
child.NavigateUrl = $"ProductList.aspx?cat={row["Id"]}";
child.Target = "mainFrame"; // 指向 iframe
// 判斷是否有子節點,決定是否啟用 PopulateOnDemand
child.PopulateOnDemand = HasChildNodes(row["Id"]);
e.Node.ChildNodes.Add(child);
}
}
private bool HasChildNodes(object categoryId)
{
// 執行 SQL 檢查是否有子分類
object result = DALHelper.ExecuteScalar($"SELECT COUNT(*) FROM Categories WHERE ParentId = {categoryId}");
return Convert.ToInt32(result) > 0;
}
<frameset cols="200,*">
<frame src="TreeMenu.aspx" name="menuFrame" />
<frame src="Welcome.aspx" name="mainFrame" />
</frameset>
或使用現代 `
<div style="display:flex;">
<div style="width:220px;"><asp:TreeView ID="TreeView1" runat="server" OnTreeNodePopulate="TreeView1_TreeNodePopulate" /></div>
<div style="flex:1;"><iframe id="mainFrame" name="mainFrame" src="Welcome.aspx" frameborder="0" style="width:100%;height:100%;"></iframe></div>
</div>