Complicated Viewstate issue on dynamic controls - c#

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:
control displays.
User enters the address info.
page posts back and the control validates the address info against a web service.
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.
The user checks a box next to the one they want to accept.
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?

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.

Two important facts:
Controls in a Repeater Item should be created in OnItemCreated and not OnItemDataBound.
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.

Related

How to filter data for a gridview based upon multiple dropdown boxes's selected values

I have an aspx webform written in C#. This page has three dropdown boxes. These dropdown boxes load values for Department, Site and Team from the corresponding tables.
Based upon logged in user's permissions an item will be preselected from these three dropdown boxed during page load. On the same page I have a gridview whose data should be filtered based upon the selected values of these three dropdown boxes.
The sql for the gridview's data source should be something like this: select * from abc where Department = <selecteditem> and Site = <selecteditem> and Team = <selecteditem>.
I have a button on the page named as Apply Filter which takes the selected items and constructs the sql, and the gridview is populated fine. However I want this filtration to happen automatically during page load event without anyone manually clicking the button after the page load.
I've tried to execute the button click event during the page event, but the filtration doesn't happen. Please let me know the best way to achieve this.
Thanks
I think you have to do like this
`protected void DropDownBoxDepartment_SelectedIndexChanged(object sender, EventArgs e)
{
// Here gives the DataSource for the DataGrid View for the DEPARTMENTSelection
}
protected void DropDownBoxSite_SelectedIndexChanged(object sender, EventArgs e)
{
// Here gives the DataSource for the DataGrid View for the SITE Selection (or Department and Site Selection whatever you want)
}
protected void DropDownBoxTeam_SelectedIndexChanged(object sender, EventArgs e)
{
// Here gives the DataSource for the DataGrid View for the TEAM Selection (or Department, Site and Team Selection whatever you want)
}`
Hope this Code Helps You....If I understand your question well.
In the Page_load event do the below:
Get the user name of the user who has logged in currently by:
String name = System.Web.HttpContext.Current.User.Identity.Name;
I hope you could figure out the permissions levels of the user with the user name.
According the permission level set the desired selected index value of your three different drop down list like below (sample)
departmentDropDownList.SelectedIndex=1;
After setting the desired value for all the three drop down do the Grid DataBind().
NOTE: I'm pretty sure you would not require this automated GridView DataBind to happen for all the post back. If that is true then put the above Page_Load code within the below condition so that this automated filtering happens only for the initial page load.
if(!IsPostBack){
}

How do I mainain the state of checkbox?

I have a list of checkboxes in gridview.
You may check one or you may check as many as you wish, up to 10.
Once you check a box or boxes in a paging app, you page to the next page, the boxes are unchecked.
How do I keep the checked boxes to remain checked until a user unchecks them?
The code I have below isn't working.
For Each r As GridViewRow In GridMaks.Rows
If CType(r.Cells(0).FindControl("makos"), CheckBox).Checked Then
Dim marko As String = baseHint & "&cup=" & r.Cells(4).Text
CType(r.Cells(0).FindControl("marko"), CheckBox).Checked = True '// added this hoping to keep checkbox checked but it doesn't work
End If
Next
Sorry for including 2 flavors c# and vb.net. I can convert c# to vb if it helps.
If you're binding data to the grid each time a page loads, the checkboxes won't persist because they're being reset. Try performing a check like the simple sample code below to only bind data when the request is not a postback.
if (IsPostBack) {
// It is a postback, don't bind data
} else {
// It is not a postback, bind data
}
Also, you may find this article regarding Persisting checkbox state while paging helpful for what you need. In the GridView's "PageChanging" event, the article says to store the row index of each row that has a checked checkbox in a List, then store that List within the ViewState. When the page changes, retrieve that List from the ViewState and repopulate the GridView checkboxes.

Is there a textboxlist control available somewhere?

There are ASP controls such as radiobuttonlist and checkboxlist and you can databind them to a database query. It's great for creating dynamic lists with user interaction. What I'm trying to do is generate a list of textboxes in the same fashion. A list of textboxes that behave the same way.
The object is to have a checkboxlist that is generated via datasource/database. When the user is finished selecting items from this list, they click a button. That list hides (using jquery) and a new list is created based on their selections. However, the new list is now a list of their selections accompanied by an empty textbox. The user fills in the textboxes for each entry and submits again which commits it to a database.
SO:
checkbox - description
checkbox - description
checkbox - description
checkbox - description
Becomes:
Description - Textbox
Description - Textbox
The reason that I'm looking for a list-type control is so that I can ultimately loop through it for submission to the database using linq. Does that make sense? My real question is if there is a control like this yet. I gave the full description in case someone has any other ideas, short of creating a custom control.
There's nothing out of the box that does what you describe no. But you can still loop through controls. I would put your form controls inside of an asp:Panel or a div with runat="server" and use something like the following code to cycle through them as you described.
foreach(Control ctl in myPanel.Controls)
{
//check control type and handle
if (ctl is TextBox)
{
//handle the control and its value here
}
}
asp:ListBox has a property named SelectionMode, which can be set to SelectionMode="Multiple" and allows you to select items you want. This is not exactly what you need but it's a simple solution.
After the selection is made in checkboxlist, make a postback to server. Here create a datatable with two columns (description & text). For every selected item in the checkboxlist add a row to this table and bind it to a gridview control. Here 'text' column will be always empty. Configure the gridview to use template column with a textbox in the itemtemplate

Insert TextBoxes into a Repeater dynamically and retrieve their value

I have a Repeater bound from SQL, containing a mixture of editable and read-only elements. When you click the "Edit" button on a row, the editable portions should convert to textboxes, and when you click "Update", it should save your changes.
Here's a (very) simplified version of the Edit and Update buttons' OnClick code:
switch(commandName)
{
case "Edit":
Label1.Visible = false; //hide read-only version
PlaceHolder1.Visible = true; //show editing version
//Dict1 is Dictionary<string, string> in this example.
foreach (var key in Dict1)
{
//insert a TextBox dynamically into the PlaceHolder
PlaceHolder1.Controls.Add(new TextBox
{
ID = "txt" + key,
Text = Dict1[key]
});
}
break;
case "Update":
//retrieve user input from dynamically-added TextBoxes
foreach (var TextBox1 in PlaceHolder1.Controls.Where(c => c.ID.StartsWith("txt")))
{
doStuff(TextBox1);
}
Label1.Visible = true; //show read-only version
PlaceHolder1.Visible = false; //hide editing version
break;
}
The problem is that my dynamically-added TextBoxes aren't there when the page posts back. I've examined PlaceHolder1.Controls in the debugger, and there are no TextBoxes in it. PlaceHolder1 itself is inside a Repeater, but I'm not rebinding the Repeater on PostBack.
I've considered using raw HTML in place of TextBox controls and pulling the values out of Request.Form, but that feels hackish to me. How can I make the dynamically-added TextBoxes persistent across postbacks?
EDIT:
There are some complications here that it's hard to show without a ton of sample code. Here are the big ones:
Each cell in the repeater can have a mixture of read-only and editable text (i.e. dynamically-inserted Labels and TextBoxes)
I don't know how many editable regions are going to be in each cell. The original text might look like blah blah #A1# blah blah #A2# blah..., and I would have to insert replacement text in place of #A1#, #A2#, etc. In edit mode, only that replacement text is editable.
When you add controls dynamically, they aren't preserved across postbacks. You have to add them to the page again after postback. I usually do it in Page_Load. Then, once they are added, their postback states will be restored correctly later in the ASP.NET page life cycle.
So,
Dynamic controls must be added each time the page is loaded,
but once you add them, ASP.NET restores their state correctly.
Hope this helps!
One possible answer would be to have the TEXTBOX pre-defined in the ITEM TEMPLATE, and then just set its' visiblity for the given row on the click event.
A second possibility would be to refactor the repeater to utilize the GRIDVIEW control instead. It supports editable templates out of the box.
Anyways, what's happening, is that since those controls are added dynamically, they're not getting recreated on the next postback. On the postback, you'll need to re-create the controls if you want to access them. BUT, don't forget that the value IS stored in the form collection:
myval = request.form["txt" + key];

On page load, navigate to a specific page where a listviewitem belongs using listview and datapager?

I have the selected DataKey in session from the ListView.
I am able to set the selection back when I comeback to this aspx page containing listview.
But when the selected item in the listview belongs to some other page (not the first listview page) then I need to also set the selected listview page to the one, where my item belongs.
I use a listview and a datapager (with template paging)
How can I find, in which page my item to be selected exists?
Can I search for the datakey value's page and then activate it?
Well the simplest solution I could apply was to also save the pageindex on session.
protected void ListView_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{ CurrentPageSessionVariable = (e.StartRowIndex / e.maximumRows);
}
Now on pageload...
dataPager1.SetPageProperties(CurrentPageSessionVariable * dataPager1.PageSize, dataPager1.MaximumRows, true);
This will ensure that when we comeback to this page, the datapager is signaled to load the specified page and show the selected item(which is separate code).

Categories

Resources