首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 使用者控制項跨控制項取值:介面契約模式完整實作 ASP.NET 使用者控制項跨控制項取值:介面契約模式完整實作

     編輯:ASP.NET 基礎

問題情境

頁面 Default.aspx 包含兩個使用者控制項 UcA.ascx、UcB.ascx。UcA 內的按鈕點擊時,需取得 UcB 內 TextBox 的值。由於控制項 ID 在命名容器中會改變 (如 ctl00$UcB1$TextBox1),直接 FindControl 易斷、耦合度高。

解決方案:介面契約

  1. 定義 IGetValue:UcB 實作,提供取值方法。
  2. 定義 IGetUserControl:頁面實作,提供取得 UcB 實例的方法。
  3. UcA 透過 this.Page 轉型呼叫,完全解耦。

程式碼實作

1. 介面定義

// IGetValue.cs
namespace MyProject.Contracts
{
    public interface IGetValue
    {
        string GetValue();
    }
}

// IGetUserControl.cs
using System.Web.UI;

namespace MyProject.Contracts
{
    public interface IGetUserControl
    {
        UserControl GetUcB(); // 回傳 UcB 實例
    }
}

2. UcB 實作 IGetValue

<%@ Control Language="C#" ClassName="UcB" %>
<asp:TextBox ID="TextBox1" runat="server" />

using System.Web.UI;
using MyProject.Contracts;

public partial class UcB : UserControl, IGetValue
{
    public string GetValue() => TextBox1.Text.Trim();
}

3. 頁面 Default.aspx 實作 IGetUserControl

<%@ Page Language="C#" %>
<%@ Register Src="UcA.ascx" TagPrefix="uc" TagName="UcA" %>
<%@ Register Src="UcB.ascx" TagPrefix="uc" TagName="UcB" %>

<html>
<body>
    <form runat="server">
        <fieldset><legend>UcA</legend><uc:UcA ID="UcA1" runat="server" /></fieldset>
        <fieldset><legend>UcB</legend><uc:UcB ID="UcB1" runat="server" /></fieldset>
    </form>
</body>
</html>

using System.Web.UI;
using MyProject.Contracts;

public partial class Default : Page, IGetUserControl
{
    public UserControl GetUcB() => UcB1; // 直接回傳強型別實例
}

4. UcA 呼叫端

<%@ Control Language="C#" ClassName="UcA" %>
<asp:Button ID="btnGet" runat="server" Text="取得 UcB 值" OnClick="btnGet_Click" />

using System.Web.UI;
using MyProject.Contracts;

public partial class UcA : UserControl
{
    protected void btnGet_Click(object sender, EventArgs e)
    {
        // 1. 取得頁面介面
        if (Page is IGetUserControl page)
        {
            // 2. 取得 UcB 實例
            var ucB = page.GetUcB();
            // 3. 轉型為值介面並取值
            if (ucB is IGetValue valueProvider)
            {
                string val = valueProvider.GetValue();
                // 顯示或處理
                ScriptManager.RegisterStartupScript(this, GetType(), "alert", $"alert('UcB 值:{val}');", true);
            }
        }
    }
}

優點分析

傳統 FindControl 介面契約模式
依賴具體 ID 字串 ("UcB1$TextBox1") 依賴介面契約,重構安全
命名容器變更即失效 不受命名容器影響
緊耦合:UcA 需知 UcB 內部結構 鬆耦合:UcA 僅知介面
難以單元測試 易 Mock 介面測試
多層巢狀控制項極難維護 層級任意深度皆適用

延伸應用:多控制項、事件通知

// 定義事件介面
public interface IValueChangedNotifier
{
    event EventHandler ValueChanged;
}

// UcB 實作
public partial class UcB : UserControl, IGetValue, IValueChangedNotifier
{
    public event EventHandler ValueChanged;
    protected void TextBox1_TextChanged(object sender, EventArgs e)
    {
        ValueChanged?.Invoke(this, new ValueChangedEventArgs(TextBox1.Text));
    }
}

// 頁面轉發事件給 UcA
public partial class Default : Page, IGetUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (UcB1 is IValueChangedNotifier notifier)
            notifier.ValueChanged += (s, args) => UcA1.OnValueChanged(args.NewValue);
    }
}

現代替代:ASP.NET Core ViewComponents / Blazor Components

  • ViewComponent:無狀態、直接呼叫、依賴注入支援。
  • Blazor:元件參數、EventCallback、CascadingParameter,原生支援跨元件通訊。
  • 新專案建議直接採用 Blazor Server/WebAssembly,避開 WebForms 控制項生命週期複雜度。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved