C# 从System.Web.UI.UserControl基类继承

C# 从System.Web.UI.UserControl基类继承,c#,asp.net,inheritance,user-controls,composite-controls,C#,Asp.net,Inheritance,User Controls,Composite Controls,首先,我想知道这是否可能。我在网上看到一些关于这件事的抱怨,但我并不完全确定 我的场景:我有一个基础图表类,它有一些所有图表都应该有的方法 public partial class BaseChart : System.Web.UI.UserControl { public BaseChart() { } public void ToggleLegend() { Chart1.Legends[0].Enabled = !Chart1.Le

首先,我想知道这是否可能。我在网上看到一些关于这件事的抱怨,但我并不完全确定

我的场景:我有一个基础图表类,它有一些所有图表都应该有的方法

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

    public void ToggleLegend()
    {
        Chart1.Legends[0].Enabled = !Chart1.Legends[0].Enabled;
    }
}
这个底图也有一些标记——设置背景色,等等。所有继承了底图的图表都应该使用这个起始标记,并且能够在此基础上进行构建

我想这样做:

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

    public HistoricalLineChart(int reportID)
        : base()
    {
        Chart1.Titles[0].Text = "Hello World";
    }
 }
其中HistoricalLineChart是没有标记的web用户控件,例如“HistoricalLineChart.ascx”

问题是图表1在HistoricalLineChart的范围内是未定义的。这里有我遗漏的东西吗


谢谢。

您可以在
基本图
中创建一个
受保护的
属性来公开图表。

不幸的是,
基本图
的标记部分实际上不是
基本图
类的一部分。标记是编译时创建的类的一部分,它继承自
BaseChart
。所以
HistoricalLineChart
只包含您在
BaseChart
中明确设置的内容,而不包含任何标记。我知道解决这个问题的唯一方法是使用复合控件或自定义服务器控件(与UserControl相比)。这有点麻烦,因为您必须以编程方式添加子控件,但应该做您想做的事情

以下是一个例子:

基本上:

  • 继承自
    CompositeControl
  • 覆盖
    CreateChildControls
    。在此方法中,您可以添加所有子控件(如图表)
  • 可选:覆盖
    渲染
    。如果除子控件外还需要自定义标记,请重写此选项。您可以在所有子控件上输出自定义标记并调用
    RenderControl
    ,以告诉它们在何处渲染输出。如果根本不重写此方法,则复合控件将按照子控件在控件集合中的顺序呈现它们
  • 以下是更多教程:


    尽管在这种情况下,通常只需要创建一个自定义控件(正如另一个答案所建议的),而且这有很多原因,但在复杂的标记使服务器控件不可行的情况下,还有一些其他方法可能很有用

    1) 创建一个基类,该基类具有实现所共有的所有功能,并继承UserControl。如果你真的想把标记作为基类的一部分,你可以把它放在一个没有代码的单独的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而不是UserControl的UserControl实现,并添加标记

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

    您还可以创建一个接口来描述应该出现在标记中的任何控件,并实现该接口。这很好,因为它提供了一个适用于UserControl(控件在标记中定义)或WebControl(控件在代码中创建)的构造,将标记的实际细节留给每个实现,但是允许您共享功能。

    如果Chart1是BaseChart的一个属性,这是正确的,但我认为在这种情况下,Chart1是在BaseChart.ascx中以声明方式创建的,BaseChart.ascx不是实际BaseChart类的一部分。那么它是什么呢?BaseChart中的代码怎么可能访问Chart1,但不能将其作为受保护属性的返回值返回?@Joel:如果您可以在
    BaseChart
    codebehind中使用它,您可以从属性返回它。@SLaks-您所说的是真的,但由于Chart1是在ascx文件中声明的,图表实例是在那里创建的,而不是在
    BaseChart
    类中创建的,因此从
    BaseChart
    继承的类需要实例化它自己的图表对象,我认为这不是肖恩想要的。@James-我意识到我在第一次评论中的措辞不正确。Chart1是
    BaseChart
    的属性,但图表对象的实际实例是在ascx文件中以声明方式创建的。因此,在Sean的
    HistoricalLineChart
    中,它确实具有Chart1属性,但从未设置过。我认为创建自定义服务器控件是一种方法。嘿,请看一下这个(我从未使用过自定义服务器控件)。我注意到,在演练中,他们正在创建一个名为“WelcomeLabel.cs”的文件。当我创建UserControl时,我使用的是Page.LoadControl(“foo.ascx”)。我知道LoadControl不能在类上调用——这是没有意义的。我能在自定义服务器控件上调用LoadControl吗?似乎所有的“自定义”都附加到了一个类中,而这个类对LoadControl没有任何用处。对于自定义服务器控件,您不需要使用
    Page.LoadControl
    。这仅适用于分部类(它加载ascx零件)。只需说
    Controls.Add(new MyControl())
    ——或者像任何类一样实例化它,并将其添加到控件集合中任意位置即可。@jamietre——这一点很好。我不知道我在想什么。我删除了我的评论。感谢到目前为止所有的帮助。我正在研究复合控件,它们似乎是我需要使用的。不过,我还有另一个顾虑,但也许你无法回答。当我第一次开始创建Microsoft图表控件时,我在运行时设置了它的属性。这些属性之一是标签的字体大小。我发现,如果我在运行时设置此字体,则Microsoft提供的一些自动放置功能似乎停止工作。然而,如果我在设计时设置了相同的字体,那么这些特性就可以工作了。你知道创建一个复合控件会如何影响它吗?你不能创建一个
    抽象的
    字段