Inheriting from a System.Web.UI.UserControl base class

9.1k views Asked by At

First off, I am wondering if this is possible. I read slight grumblings around the internet about this, but I was not entirely sure.

My scenario: I have a base chart class which has some methods which all charts should have.

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

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

There is also some mark-up for this BaseChart -- setting background colors, etc. All charts which inherit BaseChart should use this starting mark-up and be able to build upon it.

I would then like to do this:

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

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

where HistoricalLineChart is a web user control with no mark-up e.g. "HistoricalLineChart.ascx"

The problem is that Chart1 is undefined when in HistoricalLineChart's scope. Is there something that I am missing here?

Thanks.

3

There are 3 answers

8
Joel Beckham On BEST ANSWER

Unfortunately the markup portion of BaseChart is not actually part of the BaseChart class. The markup is part of a class that gets created when you compile and it inherits from BaseChart. So HistoricalLineChart only contains what you've explicitly set in BaseChart and none of the markup. The only way I know to work around this is to use a Composite Control or Custom Server Control (vs a UserControl).It's a bit more of a pain since you have to add your child controls programmatically, but should do what you want.

Here is an example: http://msdn.microsoft.com/en-us/library/3257x3ea(v=VS.100).aspx

Basically:

  1. Inherit from CompositeControl.
  2. Override CreateChildControls. In this method, you can add all of your child controls (like your chart).
  3. Optional: Override Render. Override this if you need custom markup in addition to the child controls. You can output your custom markup plus call RenderControl on all of your child controls to tell them where to render their output. If you don't override this method at all, then the composite control will render out the child controls in the order that they are in the controls collection.

Here are a couple more tutorials:

5
SLaks On

You can make a protected property in BaseChart that exposes the chart.

2
Jamie Treworgy On

Though usually one ends up just making a custom control in this situation (as the other answer suggest), and this is good for many reasons, there are a couple other approaches that may be useful in situations where complicated markup makes a server control infeasible.

1) Create a base class that has all the functionality common to your implementations and inherits UserControl. If you really want to include markup as part of the base class, you could put it in a separate usercontrol with no code, and load it from the abstract class, though this seems a little ugly. If the markup that is shared is simple, though, just render it from code instead.

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) Create UserControl implementations that inherit MyUserControl instead of UserControl, and add the markup

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

You could also create an interface that describes any controls that should appear in the markup and implement that. This is nice because it gives you a construct that is applicable to either a UserControl (where the controls are defined in markup) or a WebControl (where the controls are created in code), leaving the actual details of the markup to each implementation, but letting you share the functionality.