I have a Repeater nested inside of a GridView. On the RowDataBound event for the GridView, I set the DataSource (based on one of the row's columns) and then bind the Repeater. This works fine for the initial load, however I need to be able to add new items to the Repeater dynamically.
I append an item to the DataSource, save it to the ViewState, and where I would normally bind using a method call, I bind to the object saved to the ViewState instead. The DataSouce reflects the change, however the page does not.
What am I missing? I have the exact same setup on another page without the nesting and it works perfectly.
if (ViewState["RepeaterObj"]!=null)
{
rpt.DataSource=(IList<DataTransferObject>)ViewState["RepeaterObj"];
}
else
{
rpt.DataSource = controller.GetObj(param);
rpt.DataBind();
}
I ended up resolving the question by cutting out use of the ViewState entirely, though I thought my temporary DataSource would be lost across the postback it wasn't. I ended up going with a class-level variable which works perfectly. It seems I didn't properly understand what happens during a postback.
First of all, you shouldn't be storing a datasource in ViewState. That's pretty much the worst place you could put it.
As for your problem, I would suggest either rebinding the GridView when new items are added to the repeater, or find the repeater in the event that saves the new record and rebind it there.
I think the problem is you are not rebinding the the Repeater. You say you change how you bind to look at the ViewState object but are you actually triggering the Bind to occur? It sounds like you are not and the page is just reloading with the current data stored with the control's ViewState.
Make sure you are calling your Repeaters bind event explicitly to sure it is getting rebound.
EDIT: I suspect it might have something to do where you might need to rebind your GridView and not just the Repeater.
Related
Here is how my code is set up.
The webpage itself works like this:
You have a drop down that allows you to select between different values. Lets call it dropdown A. Depending on the value selected, a gridview gets generated.
How generation works:
When a item in the dropdown A gets selected, inside the selectedIndexChanged is a method call to a function that creates a DataTable. That datatable gets binded to the gridview inside selectIndexChanged.
When it gets bounded, onRowBoundEvent gets called, and this is where I add all the necessary controls with unique IDs.
There is a button called saved that looks at the data in gridview, and saves it.
Problem: When I press save, there are no controls in the gridview for me to find.
I can use findControl since I know all the ids, but how do I make the controls stick around?
If I bind it in the page_load, how do I know what gridview to generate since if I select a value from dropdown A, page_load still fires before I can get a selection value from dropdown A, so I can't make a simple conditional statement based on the dropdown value.
I can't show any code, sorry. But this is more of a conceptual question I have.
I was able to figure this out on my own.
PrePage_Load during the project lifecycle has access to controls. Dropdown A in my example can be accessed in PrePage_Load, allowing me to get the necessary values and set them before Page_Load starts.
For controls in the gridview, I made it so the gridview does not automatically load from viewstate, and I rebuilt the gridview myself during page_load.
I have a repeater in my page with some pre-conditions such as a checkbox list and listboxes that dictate what the datasource for the repeater brings back. A button is clicked which will databind the repeater which works fine. However if the user decides they want to add something else in or remove something they can check/uncheck some fields and then hit the button again which will rebind the repeater and change what is displayed, however the viewstate of all the current controls in the repeater will be lost.
Binding the repeater in the initialization event would not be possible because the ViewState for the checkboxlist/listbox values are not available at that point in the page lifecycle, and those values are required in order to pass as parameters into my datasource for the repeater.
What are my options for maintaining the state of my repeater controls?
repeater control binding fully recreates all of children controls inside repeater templates. Because new DataBind result may (or may not) contains extremely different data inside repeater.
What kind of controls and their state you want to maintain inside repeater? Maybe using ordinal html controls and operating with theirs through Request.Form collection would be a better way?
If you want to save data from repeater before applying new databinding, best place for making it is a Page.PreRender event. In this event all Page controls already recreated and their viewstate already restored. So you may iterate by Repeater.Items collection and save data from repeater row by row. And after saving all the data you may rebind repeater controls according current filter values from page.
I have a gridview with checkbox in Itemtemplate. What i need to do is check the condition:
(checkbox.checked==true)
if its true take the rows to another gridview. i binded the data of the gridview in
if(!PostBack)condition.
Everything was working fine until my employer said he doesnt wants the gridview to be bound in the if(!postback) condition but if i take that condition out checkbox.checked value is false always!
From the details of your question, I'm not sure if your boss wants the grid unbound or doesn't want the page bloated with the grid's ViewState, but in my experience, it's usually the latter. However, if your boss simply doesn't want the grid bound in the "if(!Postback)" condition and doesn't mind if it's bound or uses ViewState, then your boss doesn't understand web development using C# and server-side controls.
But... to answer your question, the reason the checkboxes are all unchecked is because you're rebinding the grid AFTER the ViewState has been applied. ViewState contains all the data needed in a postback condition to set the state of the checkboxes during postbacks and applies that data prior to the OnLoad (or Page_Load) event. By rebinding the grid, you are essentially wiping out anything that was posted back in ViewState and applied. To overcome this, turn ViewState off for the grid and apply the state of the checkboxes yourself AFTER you rebind the grid using the FORM collection.
If you want to do away with ViewState, here are some tips in this article.
http://www.codeproject.com/KB/viewstate/DataGridViewState.aspx
I'm trying to set the selected value of a ddl during page load ie. before databind.
This causes "selected value does not exist" errors. So I force a databind, and add a new element if it does not exist in the data source.
However it looks like when the databind is performed later in the page lifecycle that my added element(s) are removed/overwritten.
Am I setting the values in the wrong part of the life cycle?
what I'm doing seems rather hackish and I think im going about this the wrong way... is there a better way to do this?
Dont do it on PageLoad do it on the DataBound event of the ddl
Did you consider the OnPreRender event of the DDL... I think you will have everything to set the selected value there
However it looks like when the
databind is performed later in the
page lifecycle that my added
element(s) are removed/overwritten.
That is to be expected, databinding clears out the items and rebinds them again. You should look at what points in the page lifecycle you are calling DataBind and also attempting to set the Selected Value.
Have you considered Page_PreRender to set the SelectedValue? This fires after all the initialisation is done, last thing before the page is rendered to the browser. (Hopefully you won't be doing any databinding in Page_PreRender ;))
But it does not seem very logical to be setting the SelectedValue in one place only for it to be overwritten again, you should only be setting the SelectedValue once - after the final .DataBind()
However it looks like when the
databind is performed later in the
page lifecycle that my added
element(s) are removed/overwritten.
As bgs264 says, that's the behaviour of databinding by design. However, if you set the AppendDataBoundItems attribute to true for your DropDownList, this won't happen, your manually added item will remain in place.
<asp:DropDownList runat="server" id="MyDropDownList" AppendDataBoundItems="true" />
My work around to this solution is as follows:
In Page Load:
Page_Load(..)
{
if(...)
{
hidCGroup.value = objCG.CName;
}
}
In DataBound:
ddlContGroup_DataBound(..)
{
ddlContGroup.Items.Insert(0, "--Select--");
ddlContGroup.SelectedIndex = ddlContGroup.Items.IndexOf(ddlContGroup.Items.FindByText(hidCGroup.Value));
}
Now there are two things to take care of. When you are using FindByText and FindByValue always take special care of the value which you are selecting from the ddl.
Sometimes, we use a numeric item as the DataValue and a text item as the DataText, when that happens, you need to interchange FindByText and FindByValue so that the proper selection is made.
Hope this helps.
ddlExample.SelectedIndex=ddlExample.Items.IndexOf(ddlExample.Items.FindByValue(ExampleID.ToString()));
or
ddlExample.SelectedIndex=ddlExample.Items.IndexOf(ddlExample.Items.FindByText(ExampleText.ToString()));
On an ASP.NET page, I have a GridView populated with the results of a LINQ query. I'm setting the DataSource in code, then calling DataBind on it. In the GridView's RowDataBound event, I'm selectively hiding links in some GridView fields based on the query results. (For instance, I hide the "Show Parent" link of the row in question has no parent row.)
This works fine initially. But on postback (when I don't call DataBind, but the GridView stays populated through ViewState), the data displays, but the RowDataBound event (obviously) doesn't fire, and my links don't get hidden.
What's the best way to get the links to be hidden after a postback?
The RowDataBound event only fires when the GridView's data changes during the postback. The event is short-circuited for speed so it's not re-generating the exact same data unnecessarily. Use the RowCreated event to manipulate the HTML instead - it fires on every postback regardless of whether the data has changed.
Here's how I ended up solving this:
I created a serializable class with readonly properties: PK of a row, and a boolean for each link indicating whether it's enabled or not. We'll call it LinkVisibility.
I created a serializable class inheriting from KeyedCollection to hold instances of the class above.
I created a ViewState-backed property holding an instance of that collection.
In my Search procedure (populating the GridView), I clear the collection.
In RowDataBound, which initially shows/hides the links, I add a LinkVisibility instance to the collection for each row.
In Page.Load, when IsPostBack is true, I loop through the GridView rows. I look up the LinkVisibility for each one by PK in the collection (DataKeyNames is set in the GridView), and I set the links accordingly.
I don't know that this is the best way to do this, but it certainly does work, which is more than I can say for anything else I've tried.
1) You could have a Method - ProcessDataRows() that would get called once on grid_DataBound(...). And then when you need it after PostBack.
And that way you process all rows when you want.
2) You could have methods like ShowParentLink(). That are then bound to the LinkButton in the grid (if you're using an ItemTemplate) and the link would have
Visible='<%#ShowParentLink()%>'
I would have expected the viewstate to also reflect the fact that you have removed some of the links (assuming that they were removed before viewstate was saved).
Maybe thats the question you need to ask 'why do the removed links still appear in viewstate?'.
Another solution is to put the logic in the LINQ query, so that you end up with a boolean LINQ field like "ShowParentLink". Then you can just bind the Visible property of the HyperLink field to that value - no RowDataBound required.
protected void btnHazardRating_Click(object sender, EventArgs e)
{
gvPanelRole.RowDataBound += new GridViewRowEventHandler(gvPanelRole_RowDataBound);
gvPanelRole.DataSource = dtGo;
gvPanelRole.DataBind();
ModalPopup.Show();
}
void Process Rows()
{
... do something
... process complete
datagrid.DataBind();
}
A page cannot process postback events unless it is rebuilt exactly as it was before (the postback). If you re-hide your links during the page-init, then your click events and such should fire. Unfortunately, without seeing some sample code I can't get more specific.
Also the data RowDataBound does not fire because you are not data binding. You are rebuilding the page from the viewstate- "viewstate binding" for lack of a better word.