ChrisLively
ChrisLively

Reputation: 88044

Complicated Viewstate issue on dynamic controls

I have a control that is loaded dynamically and contains a repeater amongst other items such as a group of text boxes.

The control is used for address verification.

The process is:

  1. control displays.
  2. User enters the address info.
  3. page posts back and the control validates the address info against a web service.
  4. If the address isn't 100%, it displays a list of potential matches. <- this occurs in a repeater. In other words, it is databound in code.
  5. The user checks a box next to the one they want to accept.
  6. page posts back

So far, 1 - 6 work. The problem is that when the page posts back, there are no repeater items.

How can I get the repeater to load it's items without having to run another databind() operation?

Failing that, how can I run the databind() effectively? In other words, I don't have the controls street/city/state/zip values during the oninit. So, how can I reapply the viewstate changes?

Upvotes: 2

Views: 462

Answers (2)

Ian Warburton
Ian Warburton

Reputation: 15676

Two important facts:

  1. Controls in a Repeater Item should be created in OnItemCreated and not OnItemDataBound.
  2. OnItemCreated runs during a Postback without one having to call DataBind().

I've been loading user controls into repeater items and the type of user control is based on the data item being bound to the repeater. So I added the type of user control into the repeater item's viewstate so that during the OnItemCreated that runs on postback (without a data item to bind to because DataBind() has not been called) it knows what type of user control to load. The viewstate will then be applied.

protected void rpTransactions_OnItemCreated(object sender, RepeaterItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
        {
            var dataItem = e.Item.DataItem;

            string typeName;

            string viewStateKey = string.Concat("typeName", e.Item.ItemIndex);

            if (dataItem == null)
            {
                typeName = ViewState[viewStateKey].ToString();
            }
            else
            {
                typeName = dataItem.GetType().ToString();

                ViewState[viewStateKey] = typeName;
            }

            Control template = TransactionTemplateFactory(typeName);

            template.ID = "trans";

            e.Item.FindControl("phTransSpecific").Controls.Add(template);
        }
    }

If the code in OnItemDataBound runs, it fishes this user control out and binds its data to it.

Upvotes: 1

dash
dash

Reputation: 91482

Most controls are rendered as HTML form elements like <input type="text" name="myId" id="myId/>.

Part of Web Forms is really just a wrapper around all of this.

Whenever you need to get at the raw values, you can just look in the Request.Forms collection for any control values that are posted back with the name of the control you are looking for (which will usually be made up of the unique id that asp.net generates for uniqueness of controls, and your name).

This is exactly what you did - you went through the Forms collection looking at the raw form values that were POSTed to the server. It's also what you often do when you implement the IPostBackDataHandler interface when creating your own controls - you scoop the value out of Request.Forms.

The annoying thing with checkboxes is that with "standard" HTML they only get submitted if they are ticked.

Upvotes: 2

Related Questions