3

How can I build an user control that takes a list as a parameter, i.e:

<foo:TabMenu runat="server">
<Tabs>
<Tab Label="Tab1" PanelId="pnlTab1"/>
<Tab Label="Tab2" PanelId="pnlTab2"/>
<Tab Label="Tab3" PanelId="pnlTab3"/>
</Tabs>
</foo:TabMenu>
2
  • Is that an example of the ouput you want? Or the input? Commented Jan 13, 2010 at 8:38
  • That' how I want the control to be used when finished. I don't know how to build a user control that takes a list och a custom class/struct as attribute? Commented Jan 13, 2010 at 8:45

2 Answers 2

6

You need something like this. Everything is ok, but you have to complete the TabCollection class.

Edit: Pardon me, I didn't test the code. Anyway found some problems so resolved them.

UserControl

[ParseChildren(true, "Tabs"), PersistChildren(false)]
public partial class TabMenu : UserControl
{

    private TabCollection _tabs;

    [Browsable(false), PersistenceMode(PersistenceMode.InnerProperty), MergableProperty(false)]
    public virtual TabCollection Tabs
    {
        get
        {
            if (this._tabs == null)
                this._tabs = new TabCollection(this);
            return this._tabs;
        }
    }

    protected override ControlCollection CreateControlCollection()
    {
        return new TabMenuControlCollection(this);
    }

}

Tab

public class Tab : HtmlGenericControl
{

    public string Label
    {
        get { return (string)ViewState["Label"] ?? string.Empty; }
        set { ViewState["Label"] = value; }
    }

}

TabCollection

public class TabCollection : IList, ICollection, IEnumerable
{

    private TabMenu _tabMenu;

    public TabCollection(TabMenu tabMenu)
    {
        if (tabMenu == null)
            throw new ArgumentNullException("tabMenu");

        this._tabMenu = tabMenu;
    }

    public virtual int Add(Tab tab)
    {
        if (tab == null)
            throw new ArgumentNullException("tab");

        this._tabMenu.Controls.Add(tab);

        return this._tabMenu.Controls.Count - 1;
    }

    int IList.Add(object value)
    {
        return this.Add((Tab)value);
    }

    // You have to write other methods and properties as Add.

}

TabMenuControlCollection

public class TabMenuControlCollection : ControlCollection
{

    public TabMenuControlCollection(TabMenu owner) : base(owner) { }

    public override void Add(Control child)
    {
        if (child == null)
            throw new ArgumentNullException("child");

        if (!(child is TabMenu))
            throw new ArgumentException("The TabMenu control can only have a child of type 'Tab'.");

        base.Add(child);
    }

    public override void AddAt(int index, Control child)
    {
        if (child == null)
            throw new ArgumentNullException("child");

        if (!(child is TabMenu))
            throw new ArgumentException("The TabMenu control can only have a child of type 'Tab'.");

        base.AddAt(index, child);
    }

}
Sign up to request clarification or add additional context in comments.

4 Comments

Nice! I'm getting though: Foo.Presentation.Controls.TabCollection must have items of type 'Foo.Presentation.Controls.Tab'. 'Tab' is of type 'System.Web.UI.HtmlControls.HtmlGenericControl'.
any idea why visual studio only knows only about 'TabMenu' and 'Tabs', but not about 'Tab' control during editing aspx page (for autocomplete)?
@dcg Is your code exactly the same as above, or there are something different?
Should be the same. And it works fine. However, visual studio doesn't 'see' the inner children and properties when I am trying to edit the aspx file. Also, it highlights the aspx-code saying it is an invalid schema ... :-/ this is where I am losing the 'tracks'. Any idea?
1

Here is a very simple solution.

Partial Class UserControlStrings_TabMenu
    Inherits System.Web.UI.UserControl

    Private _Tabs As New MyTabsClass(Me)

    <PersistenceMode(PersistenceMode.InnerProperty)>
    Public ReadOnly Property Tabs As MyTabsClass
        Get
            Return _Tabs
        End Get
    End Property
End Class

Public Class MyTabsClass
    Inherits ControlCollection

    Sub New(ByVal owner As Control)
        MyBase.New(owner)
    End Sub

    Public Overrides Sub Add(ByVal child As System.Web.UI.Control)
        MyBase.Add(New MyTab(child))
    End Sub
End Class


Public Class MyTab
    Inherits HtmlGenericControl

    Sub New(ByVal GenericControl As HtmlGenericControl)
        MyBase.New()
        Me.Label = GenericControl.Attributes("Label")
        Me.PanelId = GenericControl.Attributes("Panelid")
    End Sub

    Public Property Label As String = String.Empty
    Public Property PanelId As String = String.Empty

    Public Overrides Function ToString() As String
        Return Me.Label & "-" & Me.PanelId
    End Function
End Class

(C# Version)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
partial class UserControlStrings_MyControl : System.Web.UI.UserControl
{


    private MyTabsClass _Tabs = new MyTabsClass(this);

    [System.Web.UI.PersistenceMode(System.Web.UI.PersistenceMode.InnerProperty)]
    public MyTabsClass Tabs {
        get { return _Tabs; }
    }
}

public class MyTabsClass : System.Web.UI.ControlCollection
{

    public MyTabsClass(System.Web.UI.Control owner) : base(owner)
    {
    }

    public override void Add(System.Web.UI.Control child)
    {
        base.Add(new MyTab(child));
    }
}


public class MyTab : System.Web.UI.HtmlControls.HtmlGenericControl
{

    public MyTab(System.Web.UI.HtmlControls.HtmlGenericControl GenericControl) : base()
    {
        this.Label = GenericControl.Attributes("Label");
        this.PanelId = GenericControl.Attributes("Panelid");
    }


    private string _Label = System.String.Empty;
    public string Label {
        get { return _Label; }
        set { _Label = value; }
    }

    private string _PanelId = System.String.Empty;
    public string PanelId {
        get { return _PanelId; }
        set { _PanelId = value; }
    }

    public override string ToString()
    {
        return this.Label + "-" + this.PanelId;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.