I have an existing ASP.NET 3.5 application with a webform containing a FormView control used to perform CRUD operations on a domain object. A new requirement adds some dynamic content to the domain object that needs to be reflected in the FormView. This means that I need to generate those controls on-the-fly based on the bound object.
I am using an ObjectDataSource for the FormView that returns the domain object for binding. The domain object will now have a property that returns a collection of Section objects with each Section containing a list of Questions. In the middle of my form, I need to display each section with the list of questions and a textbox that allows the user to input the answer.
I am able to generate the UI a number of different ways but I have yet to find a way that includes data for the dynamic fields when the page is posted back. Because I won't know the 'schema' until the FormView is data-bound, I'm wondering if I'm too late in the pipeline for postback data to be handled properly.
What is the best way for me to generate these fields so the data is posted back correctly?
UPDATE
I'm still looking for the best way to accomplish this task but I've found a solution that at least works. In short, I am creating the dynamic content in the FormView's DataBound event handler because this is the first place in the pipeline that I can always get references to the FormView's controls. Then I follow Muhammed's suggestion and pull the values right out of the Request.Form collection and put them into the EventArgs objects in the FormView's ItemInserting and ItemUpdating handlers.
This isn't so straight forward as each control has to have a unique ID that I can then use to locate the value - which isn't so bad. However, I had to implement custom logic in the data source to then map these values into the data-bound object.
All-in-all, not too bad but certainly not something I'd want to duplicate in other solutions so I'm hoping there's still a better way.
When you want to get the value from the dynamic generated field, you should get it from the Request.Form collection and pass it into the ItemInserting event of FormView. e.g.
protected void frmAsset_ItemInserting(object sender, FormViewInsertEventArgs e)
{
e.Values["FieldName"] = Request.Form[ControlClientID];
}
Please note, your controls should be recreated on postback to get the value.
Related
I am creating a server control (inheriting from CompositeControl).
The control comprises of several data bound drop down lists (and some textboxes etc).
The drop down lists form a hierarchy, so are dependent on each other... eg
ddlCountry
-ddlCounty
--ddlCity
When ddlCountry is selected, this should refresh the list of ddlCounty... and so on with the ddlCity etc.
I would like to access the value of the ddlCountry within the control, so I can set the data source for second ddl (ddlCounty) accordingly,
but in CreateChildControls() the viewstate does not seem to have loaded the ddlCountry user selection yet into the control, so I get an empty string.
I also need to provide these ddl values as a public property.
This is getting quite messy, with the use of ReCreateChildControls() etc... which I'm sure is wrong.
My Question:
Can anyone suggest the correct pattern / set of rules to abide by to create this server control
eg
initialise controls OnInit
DataBind on OnLoad
Put EnsureChildControls() at beginning of any property: get or set
I assume there must be a correct way of implementing this, but cannot find any documentation or example to get this working as you would expect of a standard control.
Thanks
I have a gridview with checkbox control as a template field and one bounded field..
The grid is binded on every postback through a function and the grid contents remain the same on every post back..now when i check one of the checkboxes and then click the button at the end of the page, I need to store that particular row information..but I'm not able to retreive that information because when I check and then click button..the page loads and then the grid again populates and then checkboxes become uncheck and no CheckedChanged event fires..Help me with this
I need to persist the state of checkbox on every postback even when it is checked..how to do this??
In the page_load event function, please use the following code for your persistent data
if (!IsPostBack)
{
//your static data
}
This particular problem is fairly common. I haven't seen any "simple" solution yet, but here are 3 separate methods I have used. Each was used because of a limitation in the system.
Solution 1
Use AJAX. By putting your controls within an update panel, you can persist the changes by making them "real-time" in the database. This is not really a "simple" solution, but in my opinion it is one of the easiest to implement. Since the change is psuedo-immediate, there is no real need to worry about post-backs and persistence.
Solution 2
Use a "change management" control of sorts. You can apply a hidden control whose value is used to keep track of any changes made in relevant controls. You would need to devise a coherent data structure that provide at least a control ID and the new value (possibly the old value if you need some kind of "roll-back" feature). This would need to be coded in JavaScript so that any changes to the hidden control's value were structured and not duplicated. Then on your postback you would need to read this control's value, make any pertinent changes, and then rebind your data as appropriate. This can be fairly cumbersome, and it would need to be well-documented in the event that you pass this application on to a successor.
Solution 3
Use the PostBack for CheckChanged events and keep all data managed in the view state. During the RowItemCreated event of the GridView you can find the checkbox control in the relevant cell and manually add the delegate handler to that control to handle the postback in the event of a CheckChanged event firing. You can then have the change immediate. The drawback to this is that PostBack events become frequent and heavy. If you're storing large amounts of data in the ViewState this also causes page load to be slow and unresponsive, so whatever structure you choose for the ViewState you'll want to keep it small.
This is possible if you are using asp.net 4.0 using
<asp:GridView id="GridView2" runat="server" EnablePersistedSelection="true">
</asp:GridView>
If you are using 3.5, you will have to retain checkbox info in viewstate. I hope this will be helpful.
http://www.codeproject.com/Articles/202938/How-to-select-multiple-records-from-the-GridView-a
Another Option:
This is how msdn have described a hotmail type gridview.. may be this can help.. this will require you to extend existing GridView Control.
http://msdn.microsoft.com/en-us/magazine/cc163612.aspx
Regards.
I have a problem with a Dev Express component, namely AspxComboBox.
My context is this: I want to dynamically generate the interface for some of my business entities. I have designed a user-control that receives some metadata and, based on that metadata, the controls adds text boxes, date-editors and combo boxes to the interface. All of those controls work like a charm when they are added to the page in a non-dynamic manner.
However, when I add them from the C# code, the following Javascript line has an error:
document.getElementById("usercontrol_combo_I").setAttribute("autocomplete", "off");
"usercontrol" is the ID of the user control I'm designing. "combo" is the ID of the combo.
The error is that the element with the ID ("usercontrol_combo_I") is not to be found in the HTML DOM.
I've discovered that if I choose not to use DataBind on the combo itself (comment out any call to the DataBind() method of the AspxComboBox instance), the JS line that has the error is never rendered (is not present in the final HTML). But, if I leave it like that, any subsequent PostBacks empties the combo list (there are no more items in the combo). The datasource of the combo is a IList instance that is assigned on every page load (even if PostBack == true).
There is a post on DevExpress's support forum that reports the same problem, but, there is no answer from the team.
Anybody here had this problem and found a way to solve it?
With ASP.NET Dev if you're binding on the Page_Load events, you need to bind in ALL requests back to the server, this includes Callbacks as well.
Now getting the HTML element and setting its attributes isn't supported. The only supported way to turn autoComplete off is for a callback to be sent to the server and turn off autoComplete on the server-side property which will update the control. Now the comboBox MUST be the one to perform the callback or wrap the box in a CallbackPanel.
Are you setting the ClientInstanceName of the ASPxComboBox too?
Actually, I've just found a simple workaround.
If I just call DataBind() on my generated control in the page_load event of the page itself, the problem is gone.
For example:
protected void Page_Load(object sender, EventArgs e)
{
base.Page_Load();
this.control.DataBind();
}
Where "control" is a UserControl that contains the combobox.
The weird thing is that I call DataBind even on PostBack and CallBack.
But, hey, it works.
I suppose that there are still a couple more things that I miss when using Devexpress.
But "practice makes perfect" !
Thanks for the reply.
I have a Custom GridView Control derived from ASP GridView Control. Now on all the Forms i have been using my CustomGridView Control.
I attach a List object to DataSource of this CustomGrid, and also store this List into ViewState so that i can manipulate this object when ever grid performs any postback.
Now every time i do insertion, updation and deletion i have to manually write code for Data Manipulation in my all Form. i.e. retrive data from ViewState and then update data or delete data or insert data into that object and store it again into ViewState.
I want a way to automatically write Code in my CustomGridView class object i.e. at one place to take care of this task. My CustomGridView Control should able to update, insert and delete for all my forms without Form writing any code at all.
In the end when its time to save the data into persistent storage i should get the final POCO object from CustomGridView Control.
This can be achieved using reflection but how?
Can you please tell me how can i achieve this task? Or what would be the best approach that i should follow?
Thanks,
Huzefa
I question whether it is best practice to store your underlying datasource within the view state. Have you considered putting this list in the session instead? It would be easier to access and you wouldn't burden your users with inflated page sizes due to overweight viewstate.
If you need to go with your stated approach, could you consider putting the code into a base form instead of trying to wedge it in the gridview? That way you only need to write the code once but it's more reasonable than trying to hack the gridview itself.
I read somewhere that one of few weaknesses in data binding model is that you never explicitly handle or create the data object that’s bound to the control and as a result you don’t have a chance to add an extra item. But I’m not sure what is meant by that.
What or how exactly would you be able to add an extra item if you were allow to explicitly create a data object? Would you basically be able to bind control to data source and let the runtime automatically fill the control with data source’s data , and additionally that control could also get an extra item from data source by manually creating it?! How would it be able to do that?!
thanx
When you use the OnItemDataBound event, you have full access to the underlying datasource object via e.Item.DataItem. You can use this data to populate any controls in the ItemTemplate via e.Item.FindControl("controlname"). You can also use functions inside the <%# %> tags to format text or calculate values.
What you have read, in my estimation, is pure crap. Up until the point of binding, I can alter the objects in question. One common scenario, for example, is adding a column to rows in a DataTable object (which is actually a collection of rows and columns). I can, in fact, alter by adding a column (let's say sum) to each row.
I can, with some restrictions on classes, do the same with other types of collections and objects.
After I have bound the object, I can still add items to the output by using the databinding method for a row, so I am still not restricted.
In general, I find those that are expounding this garbage are defending using ASP style code in an ASP.NET page.