higgsy
higgsy

Reputation: 2011

Maintaining viewstate of a repeater

I have a problem whereby the viewstate of a repeater i.e. the controls within the repeater are not maintaing their viewstate.

I have the following:

Repeater 1:

<asp:Repeater ID="rptImages" runat="server">
<ItemTemplate>
    <asp:LinkButton Text="Add" CommandName="Add" CommandArgument=<%# Eval("ID") %> runat="server" />
</ItemTemplate>
</asp:Repeater>

When the link button is clicked the value of the CommandArgument is stored in a hidden field on the page.

Upon postback I can't get the value of the hidden field until the prerender event handler has loaded. So in my prerender event I grab the value of the hidden field and store it in a List property, like so:

if (!string.IsNullOrEmpty(this.SelectedImageIDsInput.Text)) {
        this.ImageList.Add(this.SelectedImageIDsInput.Text);
    }

And the List property looks like so:

public List<string> ImageList {
    get {
        if (this.ViewState["ImageList"] == null) {
            this.ViewState["ImageList"] = new List<string>();
        }
        return (List<string>)(this.ViewState["ImageList"]);
    }
    set { this.ViewState["ImageString"] = value; }
}

Once I have stored the value into my List property I bind my second repeater (again within the prerender event):

this.rptSelectedImages.DataSource = this.LightBoxControl.ImageList;
this.rptSelectedImages.DataBind();

The second repeater has a dropdownlist and a textbox within it. The problem is that the viewstate of these child controls is not maintained. I presume it is because with each postback I am rebinding the repeater, therefore it is rebuilt. What I don't know is how I can possibly get round this? The ImageList property is only updated upon a postback, so I obviously have to rebind the repeater with each postback - how else can it be done?

Any help would be greatly appreciated.

Thanks Al

Upvotes: 7

Views: 12820

Answers (3)

Takuroandtakuro
Takuroandtakuro

Reputation: 1

This should solve your problem.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Serialization;

namespace Repeater
{
    public partial class WebForm1 : System.Web.UI.Page
    {

        private List<test> list = null;

        protected void Page_Init(object sender, EventArgs e)
        {
            if (IsPostBack == false)
            {
                list = new List<test> { new test { Title = "aaaa" }, new test { Title = "bbb" } };
                Repeater1.DataSource = list;
                Repeater1.DataBind();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected override void LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                // Load State from the array of objects that was saved at ;
                // SavedViewState.
                object[] myState = (object[])savedState;
                if (myState[0] != null)
                {
                    list = Deserialize((string)myState[0]);
                    Repeater1.DataSource = list;
                    Repeater1.DataBind();
                }
                if (myState[1] != null)
                    base.LoadViewState(myState[1]);
            }
        }

        protected override object SaveViewState()
        {
            object baseState = base.SaveViewState();
            object[] allStates = new object[2];
            allStates[1] = baseState;
            allStates[0] = Serialize();
            return allStates;
        }

        string Serialize()
        {
            var writer = new StringWriter();
            var serializer = new XmlSerializer(typeof(List<test>));
            serializer.Serialize(writer, list);

            var xml = writer.ToString();
            return xml;
        }
        List<test> Deserialize(string xml)
        {
            var serializer = new XmlSerializer(typeof(List<test>));

            var deserializedBook = (List<test>)serializer.Deserialize(new StringReader(xml));
            return deserializedBook;
        }
    }

    public class test
    {
        public string Title { get; set; }
    }
}

Upvotes: 0

TheCodeKing
TheCodeKing

Reputation: 19230

If you are rebinding the repeater, you need to do it on Init before the ViewState is loaded.

You should also check the IsPostback flag and only Bind the repeater when the page is not posted back.

To clarify if your second repeater is bound on PreRender then ViewState cannot be used to persist the controls, because they simply don't exist when ViewState is loaded - after Init, and before PreLoad.

You either need to continue binding on every postback, or store or list in Session so that you have access to the list to bind once on Init, (or on change).

Upvotes: 13

Mikael &#214;stberg
Mikael &#214;stberg

Reputation: 17176

I don't see the point of copying the CommandArgument property to a hidden field. What you should do is to use the ItemCommand event on the Repeater and use event bubbling. You can handle the Click event on you LinkButton like this:

repeater.ItemCommand += (sender, eventArgs) => {  
   var commandArgument = eventArgs.CommandArguments;
   ImageList.Add(commandArgument);
   rptSelectedImages.DataSource = ImageList;
   rptSelectedImages.DataBind();
}

Upvotes: 0

Related Questions