2011-02-28 126 views
3

首先,我想知道這是否可能。我在網上讀到關於這個的輕微抱怨,但我並不完全確定。繼承自System.Web.UI.UserControl基類

我的場景:我有一個基本圖表類,它有一些所有圖表都應該有的方法。

public partial class BaseChart : System.Web.UI.UserControl 
{ 
    public BaseChart() 
    { 
    } 

    public void ToggleLegend() 
    { 
     Chart1.Legends[0].Enabled = !Chart1.Legends[0].Enabled; 
    } 
} 

也有一些標記爲這個BaseChart - 設置背景顏色等,這些繼承BaseChart應該使用這個起點標記和能夠建立在其上的所有圖表。

話,我想這樣做:

public partial class HistoricalLineChart : BaseChart 
{ 
    public HistoricalLineChart() 
     : base() 
    { 
    } 

    public HistoricalLineChart(int reportID) 
     : base() 
    { 
     Chart1.Titles[0].Text = "Hello World"; 
    } 
} 

其中HistoricalLineChart是沒有加價例如web用戶控制「HistoricalLineChart.ascx」

問題是在HistoricalLineChart的作用域中Chart1未定義。有什麼我在這裏失蹤?

謝謝。

回答

1

不幸的是,BaseChart的標記部分實際上並不是BaseChart類的一部分。標記是在編譯時創建的類的一部分,它繼承自BaseChart。因此HistoricalLineChart只包含您在BaseChart中明確設置的內容,並且沒有任何標記。我知道要解決這個問題的唯一方法是使用複合控件或自定義服務器控件(相對於UserControl)。由於您必須以編程方式添加子控件,但是應該按照自己的需要進行操作,這有點多痛苦。

下面是一個例子:http://msdn.microsoft.com/en-us/library/3257x3ea(v=VS.100).aspx

基本上:

  1. 繼承CompositeControl
  2. 替代CreateChildControls。在這種方法中,您可以添加所有的子控件(如圖表)。可選:覆蓋Render。如果除了子控件需要自定義標記,則覆蓋此選項。您可以輸出自定義標記,並在您的所有子控件上調用RenderControl,以告訴它們在哪裏呈現其輸出。如果您完全不覆蓋此方法,則複合控件將按照它們在控件集合中的順序呈現子控件。

這裏有一對夫婦更教程:

+0

我認爲創建自定義服務器控件是適合您的方式。 – TheGeekYouNeed 2011-02-28 22:05:01

+0

嘿,所以只是看着這(我從來沒有與自定義服務器控件一起工作)。我注意到,在演練中,他們正在創建一個名爲「WelcomeLabel.cs」的文件。 當我創建我的UserControl時,我使用Page.LoadControl(「foo.ascx」)。我知道LoadControl不能在類上調用 - 這是沒有意義的。我能夠在自定義服務器控件上調用LoadControl嗎?看起來好像所有的'custom'都附加在LoadControl無用的類中。 – 2011-02-28 22:13:58

+1

您無需爲自定義服務器控件使用「Page.LoadControl」。這只是部分類需要(它加載了ascx部分)。只需說出Controls.Add(new MyControl()) - 或者像任何類那樣實例化它並將它添加到控件集合中。 – 2011-02-28 22:40:02

0

您可以在BaseChart中使protected屬性公開該圖表。

+0

如果Chart1是BaseChart的一個屬性,那會是真的,但我認爲在這種情況下Chart1是在BaseChart.ascx中聲明創建的,它不是實際的BaseChart類的一部分。 – 2011-02-28 22:02:54

+0

但是那是什麼?以及BaseChart中的代碼如何訪問Chart1,但不能將其作爲受保護屬性的返回值返回? – 2011-02-28 23:04:34

+0

@Joel:如果你可以在'BaseChart'代碼隱藏中使用它,你可以從屬性中返回它。 – SLaks 2011-02-28 23:08:47

2

雖然通常一個最終只是在這種情況下做出一個自定義的控制(如其他答案建議),這有很多原因,還有其他一些方法這在複雜的標記使服務器控制不可行的情況下可能很有用。

1)創建一個基類,它具有您實現的所有通用功能並繼承UserControl。如果你真的想把標記作爲基類的一部分,你可以把它放在一個不帶代碼的單獨的用戶控件中,並從抽象類中加載它,雖然這看起來有點難看。但是,如果共享的標記很簡單,那麼只需從代碼中提取即可。

public abstract class MyUserControl: UserControl 
{ 
    public Chart Chart1; 
    public void ToggleLegend() 
    { 
     Chart1.Legends[0].Enabled = !Chart1.Legends[0].Enabled; 
    } 
    public override void CreateChildControls() 
    { 
     Controls.Add(Page.LoadControl("path/to/mymarkup/control")); 
     // or add them in code 
     BuildBaseControls(); 
    } 
} 

2)創建用戶控件實現繼承的MyUserControl,而不是用戶控件,並添加標記

public partial class HistoricalLineChart : MyUserControl 
{ 
    public HistoricalLineChart(int reportID) 
     : base() 
    { 
     Chart1.Titles[0].Text = "Hello World"; 
    } 
} 

您還可以創建一個描述應該出現在標記並實施任何控制的接口。這很好,因爲它給你一個適用於UserControl(其中控件是在標記中定義的)或WebControl(其中控件是在代碼中創建的)的構造,將標記的實際細節留給每個實現,但是讓你分享功能。

+0

您無法創建「抽象」字段。 – SLaks 2011-02-28 23:10:28

+0

我認爲我已經修復,當你評論:)是啊,它不應該是抽象的。 – 2011-02-28 23:14:22