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

ASP.NET 2.0 型別化樣式屬性開發:建立專屬 Style 衍生類別完整實作

     編輯:關於ASP.NET

什麼是型別化樣式?

型別化樣式 是繼承自 System.Web.UI.WebControls.Style 的自訂類別,封裝一組相關的樣式屬性(如 BackImageUrl、HorizontalAlign、Wrap),並能自動參與視圖狀態管理、樣式合併、複製、CSS 渲染。控制項的 ControlStyle 屬性即為此型別,提供強型別、設計時智慧提示、屬性視窗分類顯示等優勢。

實作五大必要覆寫

方法/屬性用途必要性
屬性定義 + ViewState 儲存將樣式值存入 ViewState,跨回傳保持必要
FillStyleAttributes (舊版 AddAttributesToRender)輸出 CSS 樣式屬性至 HtmlTextWriter必要
CopyFrom從另一 Style 物件完整複製屬性值必要
MergeWith合併另一 Style 的非預設值(樣式繼承鏈核心)必要
Reset重設為預設狀態,清除 ViewState 項目必要

完整實作範例:MyPanelStyle + MyPanel 控制項

1. 定義 MyPanelStyle

public class MyPanelStyle : Style
{
    public MyPanelStyle() : base() { }
    public MyPanelStyle(StateBag bag) : base(bag) { }

    private string _backImageUrl;
    private HorizontalAlign _horizontalAlign = HorizontalAlign.NotSet;
    private bool _wrap = true;

    [DefaultValue(""), UrlProperty(), Description("背景圖片 URL")]
    public string BackImageUrl
    {
        get { return _backImageUrl; }
        set { _backImageUrl = value; }
    }

    [DefaultValue(HorizontalAlign.NotSet), Description("水平對齊")]
    public HorizontalAlign HorizontalAlign
    {
        get { return _horizontalAlign; }
        set { _horizontalAlign = value; }
    }

    [DefaultValue(true), Description("是否允許換行")]
    public bool Wrap
    {
        get { return _wrap; }
        set { _wrap = value; }
    }

    protected override void FillStyleAttributes(CssStyleCollection css, IUrlResolutionService urlResolver)
    {
        base.FillStyleAttributes(css, urlResolver);
        if (!string.IsNullOrEmpty(_backImageUrl))
            css["background-image"] = "url(" + urlResolver.ResolveClientUrl(_backImageUrl) + ")";
        if (_horizontalAlign != HorizontalAlign.NotSet)
            css["text-align"] = _horizontalAlign.ToString().ToLower();
        if (!_wrap)
            css["white-space"] = "nowrap";
    }

    public override void CopyFrom(Style s)
    {
        base.CopyFrom(s);
        MyPanelStyle mps = s as MyPanelStyle;
        if (mps != null)
        {
            _backImageUrl = mps._backImageUrl;
            _horizontalAlign = mps._horizontalAlign;
            _wrap = mps._wrap;
        }
    }

    public override void MergeWith(Style s)
    {
        if (IsEmpty) { CopyFrom(s); return; }
        MyPanelStyle mps = s as MyPanelStyle;
        if (mps != null && !mps.IsEmpty)
        {
            if (!string.IsNullOrEmpty(mps._backImageUrl)) _backImageUrl = mps._backImageUrl;
            if (mps._horizontalAlign != HorizontalAlign.NotSet) _horizontalAlign = mps._horizontalAlign;
            _wrap = mps._wrap;
        }
        base.MergeWith(s);
    }

    public override void Reset()
    {
        _backImageUrl = null;
        _horizontalAlign = HorizontalAlign.NotSet;
        _wrap = true;
        base.Reset();
    }
}

2. 控制項使用型別化樣式

[ToolboxData("<{0}:MyPanel runat=server></{0}:MyPanel>")]
public class MyPanel : Panel
{
    private MyPanelStyle _myPanelStyle;

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty)]
    public MyPanelStyle MyPanelStyle
    {
        get
        {
            if (_myPanelStyle == null)
            {
                _myPanelStyle = new MyPanelStyle();
                if (IsTrackingViewState) ((IStateManager)_myPanelStyle).TrackViewState();
            }
            return _myPanelStyle;
        }
    }

    protected override Style CreateControlStyle()
    {
        return new MyPanelStyle(ViewState);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        // 將 MyPanelStyle 套用至外層 div
        MyPanelStyle.AddAttributesToRender(writer, this);
        writer.RenderBeginTag(HtmlTextWriterTag.Div);
        RenderContents(writer);
        writer.RenderEndTag();
    }
}

3. 網頁宣告式使用

<cc:MyPanel ID="panel1" runat="server">
    <MyPanelStyle BackImageUrl="~/images/bg.png" HorizontalAlign="Center" Wrap="false" />
    <asp:Label runat="server" Text="標題置中、背景圖、不換行" />
</cc:MyPanel>

設計時支援強化

  • [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]:讓屬性視窗展開子屬性編輯。
  • [NotifyParentProperty(true)]:子屬性變更通知父控制項標記為 Dirty,觸發 ViewState 儲存。
  • [PersistenceMode(PersistenceMode.InnerProperty)]:支援標記內嵌 `` 語法。
  • 加上 [Category("Appearance")]、[Description("...")]、[DefaultValue(...)] 豐富屬性視窗資訊。

進階:多樣式控制項(如 GridView 的 RowStyle/AlternatingRowStyle)

定義多個 TableItemStyle 型別屬性,各自管理不同 UI 區塊樣式:

[PersistenceMode(PersistenceMode.InnerProperty)]
public TableItemStyle HeaderStyle { get { ... } }
[PersistenceMode(PersistenceMode.InnerProperty)]
public TableItemStyle RowStyle { get { ... } }
[PersistenceMode(PersistenceMode.InnerProperty)]
public TableItemStyle AlternatingRowStyle { get { ... } }

渲染時依資料列索引套用對應 Style。

常見錯誤與解決

錯誤原因修正
樣式不生效、不輸出 CSS未呼叫 AddAttributesToRender、或 FillStyleAttributes 未正確輸出確保 Render 方法呼叫 Style.AddAttributesToRender(writer, this)
ViewState 不保存、回傳後樣式消失屬性未存入 ViewState、或未 TrackViewState屬性 setter 呼叫 ViewState["Prop"] = value;建構子傳入 ViewState
設計時屬性視窗無法展開缺少 DesignerSerializationVisibility.Content加上該屬性於樣式屬性定義上
MergeWith 行為異常未正確判斷 IsEmpty、未呼叫 base.MergeWith遵循標準模式:IsEmpty 檢查 → 型別轉換 → 合併非預設值 → base.MergeWith

總結

型別化樣式是 ASP.NET 2.0 控制項外觀架構的核心。掌握 Style 繼承、ViewState 整合、FillStyleAttributes CSS 輸出、CopyFrom/MergeWith/Reset 樣式鏈操作,並配合設計時屬性,即可打造專業級、可視化編輯、強型別安全的控制項樣式系統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved