calin
calin

Reputation: 58

Persisting state of custom ASP.Net control

I have a custom control that mimics to some extent the built in ASP.Net CheckboxList control. On the render event I generate a UL>LI>Checkbox#customId structure based on the DataSource the control is getting.

My biggest puzzle is that, even though the input HTML elements get rendered on the page, when submitting back the page, the Request.Form collection has no data related to these inputs.

So, my question is this: Once a PostBack is triggered, is there a way to get the inputs checked by the user?

Thanks in advance, Kali

Upvotes: 1

Views: 893

Answers (2)

calin
calin

Reputation: 58

As James correctly pointed out, it was a matter of page life cycle.

What I was initially doing was to write the UL>LI>Input structure on the Render method, by writing to the HTmlTextWriter. While this method actually created the expected HTML, when postbacking, the FORM property did not carry back any of the checked inputs.

What I've end up doing was to create the controls on CreateChildControls using Html Server Controls. This way, I was able to retrieve the information I was looking for from the FORM collection.

Also, as James pointed out in his reply, in order to persist the state from one request to the other, the LoadViewState and SaveViewState methods need to be overridden.

Upvotes: 0

James Johnson
James Johnson

Reputation: 46047

Typically, a custom server control will implement the SaveViewState, LoadViewState, and TrackViewState methods to manage the state of controls.

I don't know how you're control is built so I can't give you the exact code, but here's an example of those methods being used in a control that I created:

protected override void LoadViewState(object savedState)
{
    if (savedState != null)
    {
        object[] state = (object[])savedState;

        if (state[0] != null)
            base.LoadViewState(state[0]);
        if (state[1] != null)
            ((IStateManager)ItemStyle).LoadViewState(state[1]);
        if (state[2] != null)
            ((IStateManager)headerStyle).LoadViewState(state[2]);
        if (state[3] != null)
            ((IStateManager)AlternatingItemStyle).LoadViewState(state[3]);
    }
}

protected override object SaveViewState()
{
    object[] state = new object[4];

    state[0] = base.SaveViewState();
    state[1] = itemStyle != null ? ((IStateManager)itemStyle).SaveViewState() : null;
    state[2] = headerStyle != null ? ((IStateManager)headerStyle).SaveViewState() : null;
    state[3] = alternatingItemStyle != null ? ((IStateManager)alternatingItemStyle).SaveViewState() : null;

    return state;
}

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

    if (itemStyle != null)
        ((IStateManager)itemStyle).TrackViewState();
    if (headerStyle != null)
        ((IStateManager)headerStyle).TrackViewState();
    if (alternatingItemStyle != null)
        ((IStateManager)alternatingItemStyle).TrackViewState();
}

Aside from the above methods, if you want to reload information from the Request object, you can implement the IPostBackDataHandler interface, which requires these two methods:

public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
    string somePostedValue = postCollection["SomePostedValue"];
    string anotherPostedValue = postCollection["AnotherPostedValue"];
}

public virtual void RaisePostDataChangedEvent()
{

}

Upvotes: 2

Related Questions