| 類型 | 副檔名 | 建立方式 | 重用層級 | 適用場景 |
|---|---|---|---|---|
| 使用者控件 | .ascx | 設計師拖拉 + 程式碼後置,類似迷你頁面 | 專案內共用 | 頁面區塊重用 (Header、Footer、選單、搜尋列、分頁器) |
| 自訂控件 | .cs (類別庫) | 繼承 Control/WebControl,完整渲染控制 | 跨專案、NuGet 套件 | 複雜互動元件 (Grid、Tree、圖表)、第三方元件庫 |
| Server Control (內建) | - | GridView、Repeater、DropDownList... | - | 標準資料綁定、表單輸入 |
Header.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Header.ascx.cs" Inherits="Demo.Controls.Header" %>
<!-- 無需 html/head/body/form 標籤 -->
<header class="site-header">
<div class="container">
<h1><asp:Literal ID="litSiteTitle" runat="server" /></h1>
<nav>
<asp:HyperLink ID="hlHome" runat="server" Text="首頁" NavigateUrl="~/" /> |
<asp:HyperLink ID="hlAbout" runat="server" Text="關於我們" NavigateUrl="~/About.aspx" /> |
<asp:HyperLink ID="hlContact" runat="server" Text="聯絡我們" NavigateUrl="~/Contact.aspx" />
</nav>
</div>
</header>
<style>
.site-header { background: #343a40; color: white; padding: 1rem 0; }
.site-header a { color: #adb5bd; text-decoration: none; margin: 0 0.5rem; }
.site-header a:hover { color: white; }
</style>
Header.ascx.cs
using System;
using System.Web.UI;
namespace Demo.Controls
{
public partial class Header : System.Web.UI.UserControl
{
// 公開屬性:允許父頁面設定標題
public string SiteTitle
{
get => litSiteTitle.Text;
set => litSiteTitle.Text = value;
}
// 公開方法:動態切換導航狀態
public void SetActiveNav(string navId)
{
// 實作:依 navId 找對應 HyperLink 加上 CSS class
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// 預設值
if (string.IsNullOrEmpty(litSiteTitle.Text))
litSiteTitle.Text = "我的網站";
}
}
}
}
<%@ Page Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Demo.Default" %>
<!-- 註冊控件:Src=相對路徑, TagPrefix=自訂前綴, TagName=標籤名稱 -->
<%@ Register Src="~/Controls/Header.ascx" TagPrefix="uc" TagName="Header" %>
<%@ Register Src="~/Controls/Footer.ascx" TagPrefix="uc" TagName="Footer" %>
<%@ Register Src="~/Controls/SearchBox.ascx" TagPrefix="uc" TagName="SearchBox" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<!-- 使用註冊的 TagPrefix:TagName -->
<uc:Header ID="ucHeader" runat="server" SiteTitle="首頁 - 我的系統" />
<main class="container">
<uc:SearchBox ID="ucSearch" runat="server" OnSearch="ucSearch_Search" />
<h2>歡迎來到首頁</h2>
<p>這裡是主要內容區...</p>
</main>
<uc:Footer ID="ucFooter" runat="server" CompanyName="Demo Corp" />
</asp:Content>
SearchBox.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SearchBox.ascx.cs" Inherits="Demo.Controls.SearchBox" %>
<div class="search-box">
<asp:TextBox ID="txtKeyword" runat="server" CssClass="form-control" placeholder="輸入關鍵字..." />
<asp:Button ID="btnSearch" runat="server" Text="搜尋" CssClass="btn btn-primary" OnClick="btnSearch_Click" />
</div>
public partial class SearchBox : System.Web.UI.UserControl
{
// 定義事件委派
public event EventHandler Search;
// 事件參數類別
public class SearchEventArgs : EventArgs
{
public string Keyword { get; set; }
}
protected void btnSearch_Click(object sender, EventArgs e)
{
string kw = txtKeyword.Text.Trim();
// 觸發事件,父頁面處理
Search?.Invoke(this, new SearchEventArgs { Keyword = kw });
}
// 公開屬性:預設關鍵字
public string DefaultKeyword
{
get => txtKeyword.Text;
set => txtKeyword.Text = value;
}
}
Default.aspx.cs
protected void ucSearch_Search(object sender, SearchBox.SearchEventArgs e)
{
// 父頁面接收事件,執行查詢、重導向、綁定 GridView 等
Response.Redirect($"~/SearchResults.aspx?q={Server.UrlEncode(e.Keyword)}");
}
// 在控件內取得父頁面上的其他控件
var master = this.Page.Master;
var header = master.FindControl("ucHeader") as Header;
header?.SetActiveNav("home");
// 或在父頁面取得控件實例
var searchBox = FindControl("ucSearch") as SearchBox;
searchBox.DefaultKeyword = "預設關鍵字";
Site.Master
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="Demo.SiteMaster" %>
<%@ Register Src="~/Controls/Header.ascx" TagPrefix="uc" TagName="Header" %>
<%@ Register Src="~/Controls/Footer.ascx" TagPrefix="uc" TagName="Footer" %>
<html><body>
<form id="form1" runat="server">
<uc:Header ID="ucHeader" runat="server" />
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
<uc:Footer ID="ucFooter" runat="server" />
</form></body></html>
內容頁面**無需重複註冊**,直接使用 `
<configuration>
<system.web>
<pages>
<controls>
<add tagPrefix="uc" tagName="Header" src="~/Controls/Header.ascx" />
<add tagPrefix="uc" tagName="Footer" src="~/Controls/Footer.ascx" />
<add tagPrefix="uc" tagName="SearchBox" src="~/Controls/SearchBox.ascx" />
</controls>
</pages>
</system.web>
</configuration>
所有 .aspx 自動可用 `
| 問題 | 原因 | 解決 |
|---|---|---|
| 控件內控件 ID 衝突 | 多次引用同一控件,ID 重複 | ASP.NET 自動處理 NamingContainer,確保 `ClientIDMode="AutoID"` (預設) 即可 |
| 控件事件不觸發 | `AutoEventWireup="false"` 或事件綁定錯誤 | 檢查 `@Control AutoEventWireup="true"`、按鈕 `OnClick` 對應方法名 |
| 樣式/Script 重複引用 | 每個控件都寫 ` |