views:

176

answers:

3

Does anyone know how to make nested server controls accept nested html without "injecting" it out from serverside, ie.

<uc1:CustomServerControl runat="server">
     <NestedControl></NestedControl>
     <NestedControl2></NestedControl2>
</uc1:CustomServerControl>

but to do this:

<uc1:CustomServerControl runat="server">
    <div>
        <NestedControl>
           <a href="#"></a>
        </NestedControl>
       <NestedControl2></NestedControl2>
    </div>
</uc1:CustomServerControl>
A: 

Try this:

[ToolboxData("..."), ParseChildren(false), PersistChildren(true)]
public class CustomServerControl : WebControl, INamingContainer
{
}
Mehdi Golchin
My problem is that I have to set ParseChildren(true), as the main servercontrol contains nested controls that needs to be rendered, I need to combine the functionality of treating the control children as properties and render html.
BK
I think, it's not possible exactly. As you demonstared in the second code snippet, you put an CustomServerControl properties onto the inner HTML of a div which the server controlcan not parse them. I don't know what you want to do and why? If you explain the ServerControl task, maybe I can help.
Mehdi Golchin
A: 

The purpose of this basicly is to have a custom Generic tag library, whick in this case will speak to a underlying object model. The objectmodel is responsible for splitting up articles into its respective parts, ie, Headline, blurb, Images, Comments etc. In this case I'm woring with a collection of them, and by specifying the inner tags, you basicly apply a filter onto what parts of the articles in the section you want to see.

   <uc1:Section runat="server">     
     <HeadLine></HeadLine>     
     <Blurb></Blurb>     
     <Body></Body>
   </uc1:Section>

Based on what the user specify by only tagging whatever he needs, the respective content will then be written to the frontend.

Now this works wonderfully well, except in one or two cases where you actually need some kind of internal structure to each of the individual parts of an article, and then projecting that onto the entire collection, like having a <table> where the headline should go into one <td> and the rest into another <td>

Hope it makes sense!!

BK
A: 

Try this:

Section.cs:

[ToolboxData("<{0}:Section runat=\"server\" />")]
public class Section : WebControl, INamingContainer
{
    private SectionPartCollection _parts;

    [Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
    public SectionPartCollection Parts
    {
        get
        {
            if (this._parts == null)
            {
                this._parts = new SectionPartCollection();
                if (this.IsTrackingViewState)
                    ((IStateManager)this._parts).TrackViewState();
            }
            return this._parts;
        }
    }

    [Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
    public ITemplate LayoutTemplate { get; set; }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        if (this.LayoutTemplate != null)
        {
            this.LayoutTemplate.InstantiateIn(this);

            foreach (SectionPart part in this.Parts)
            {
                Control placeHolder = this.FindControl(part.PlaceHolderID);
                if (placeHolder != null)
                    if (part.ContentTemplate != null)
                        part.ContentTemplate.InstantiateIn(placeHolder);
            }
        }
    }

    protected override void LoadViewState(object savedState)
    {
        object[] states = (object[])savedState;

        base.LoadViewState(states[0]);

        if (states[1] != null)
            ((IStateManager)this.Parts).LoadViewState(states[1]);
    }

    protected override object SaveViewState()
    {
        object[] states = new object[2];

        states[0] = base.SaveViewState();

        if (this._parts != null)
            states[1] = ((IStateManager)this.Parts).SaveViewState();

        return states;
    }

    protected override void TrackViewState()
    {
        base.TrackViewState();

        if (this._parts != null)
            ((IStateManager)this._parts).TrackViewState();
    }
}

SectionPart.cs:

[DefaultProperty("PartName")]
public class SectionPart : IStateManager
{
    private StateBag _viewState;
    private bool _isTrackingViewState;

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

    [Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
    public ITemplate ContentTemplate { get; set; }

    public void SetDirty()
    {
        if (this._viewState != null)
            this.ViewState.SetDirty(true);
    }

    [Browsable(false)]
    protected StateBag ViewState
    {
        get
        {
            if (this._viewState == null)
            {
                this._viewState = new StateBag(false);
                if (this._isTrackingViewState)
                    ((IStateManager)this._viewState).TrackViewState();
            }
            return this._viewState;
        }
    }

    protected virtual bool IsTrackingViewState
    {
        get { return this._isTrackingViewState; }
    }

    protected virtual void LoadViewState(object state)
    {
        if (state != null)
            ((IStateManager)this.ViewState).LoadViewState(state);
    }

    protected virtual object SaveViewState()
    {
        if (this._viewState != null)
            return ((IStateManager)this._viewState).SaveViewState();
        return null;
    }

    protected virtual void TrackViewState()
    {
        this._isTrackingViewState = true;
        if (this._viewState != null)
            ((IStateManager)this._viewState).TrackViewState();
    }

    bool IStateManager.IsTrackingViewState
    {
        get { return this.IsTrackingViewState; }
    }

    void IStateManager.LoadViewState(object state)
    {
        this.LoadViewState(state);
    }

    object IStateManager.SaveViewState()
    {
        return this.SaveViewState();
    }

    void IStateManager.TrackViewState()
    {
        this.TrackViewState();
    }

}

SectionPartCollection.cs:

public class SectionPartCollection : StateManagedCollection
{

    public SectionPart this[int index]
    {
        get { return (SectionPart)((IList)this)[index]; }
    }

    public void Add(SectionPart part)
    {
        if (part == null)
            throw new ArgumentNullException("part");

        ((IList)this).Add(part);
    }

    public void Insert(int index, SectionPart part)
    {
        if (part == null)
            throw new ArgumentNullException("part");

        ((IList)this).Insert(index, part);
    }

    public void Remove(SectionPart part)
    {
        if (part == null)
            throw new ArgumentNullException("part");

        ((IList)this).Remove(part);
    }

    public void RemoveAt(int index)
    {
        ((IList)this).RemoveAt(index);
    }

    protected override void SetDirtyObject(object o)
    {
        ((SectionPart)o).SetDirty();
    }

}

Example:

<uc:Section ID="Section1" runat="server">
    <LayoutTemplate>
        <table>
            <tr>
                <td id="TitlePlaceHolder" runat="server">
                </td>
            </tr>
            <tr>
                <td id="BodyPlaceHolder" runat="server">
                </td>
            </tr>
        </table>
    </LayoutTemplate>
    <Parts>
        <uc:SectionPart PlaceHolderID="TitlePlaceHolder">
            <ContentTemplate>
                <span>Title</span>
            </ContentTemplate>
        </uc:SectionPart>
        <uc:SectionPart PlaceHolderID="BodyPlaceHolder">
            <ContentTemplate>
                <p>
                    Some content...</p>
            </ContentTemplate>
        </uc:SectionPart>
    </Parts>
</uc:Section>
Mehdi Golchin
You gave me some ideas, I'll come back to you once implemented
BK