2011-02-28 202 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