I am updating an existing ASP .NET site. This site has a custom grid control class that extends the GridView control to add a few features. Many pages in the site use the built in declarative two-way binding feature that is built into the base GridView, i.e. column templates make calls to Bind() so that data can be shown and updated automatically. This works fine in most cases. However, when binding DropDownList controls there is now a problem.
Recently I had to add a feature that allows records in some tables to be marked as 'Closed', i.e. they can no longer be referenced by new records being inserted into other tables.
When editing a data grid row that has a DropDownList of child records that can be closed, the SelectedValue property might be bound to an ID that does not exist in the list. This causes an ArgumentOutOfRange exception to be thrown. I just want the DropDownList to default to no selection if the record is closed and therefore not in the list.
I'm looking for the easiest way to solve this. If possible I don't want to have to make a lot of changes to existing code.
I can programmatically set the selected index of the DropDownList in the RowDataBound event. But I can't find a way of updating the value whilst keeping the existing update functionality.
The actual question:
Is there some way to extend the DropDownList to make it ignore invalid values for the SelectedValue property? The only example I have seen so far does not work. I think that the DropDownList caches the value in case it has not yet had its DataSource property set, so overriding the SelectedValue property is not sufficient.
Alternatively, if there is a way to use the OnRowUpdating event to manually add the data to the update then that would be OK. I have tried adding values to the NewValues dictionary on the GridViewUpdateEventArgs class but it doesn't seem to work. Note that the grids are bound to lists of objects, not DataSourceControl derived controls.
Any help would be appreciated. Thanks.
If anyone's interested, I think I solved this by overriding the PerformDataBinding method and catching the ArgumentOutOfRangeException there. I suspect that the SelectedValue property might need to be overridden as well if the order in which the two properties are bound can vary.
Related
I have some questions about how and when data sources are bound in the page lifecycle, and I can't seem to find the answers anywhere.
I have a gridview which is bound to a data source at design time. One of the parameters for the DS is the selected value of a dropdown list. These dropdown lists are also databound to retreive their options, and the dropdowns have their auto-postback property set true. Now some things are confusing me about this.
Most of the time changing the value of the dropdown will reload the gridview with the new parameter, and it's not necessary to manually call databind() on the gridview in order to do so. However there are situations where the gridview is not rebound, and I'm not sure what these conditions are. When will a data-source be rebound automatically upon parameter change, and when do you need to call databind manually from code?
Does calling databind from codebehind prevent the automatic databind event from firing, or will they both fire, resulting in a wasteful extra query of the data source?
If the former, is there a way to stop the extra databind from occurring without having to move everything into code behind and lose the convenience of setting up data sources for the controls in the design view?
Are the answers to these questions documented on any official sources? (MSDN, etc)
I can't be sure without looking at you code, but you probably want to read about ViewState.
Once the control has been loaded, the data stays in the viewstate. You generally want to do the DataBinding on (!IsPostBack) event so that on postbacks you do not need to rebind the data from the DB.
I have a few reasons that I need this to happen, but suffice it to say that when I use the event handler for the RadioButtonList the sender object returns as just the RadioButtonList, and I need more information from the GridView because that's how I can uniquely identify which record my RadioButtonList is tied to.
I added an "OnSelectedIndexChanged" property to my GridView but it doesn't fire/handle when I want it to. I'm assuming this has something to do with the way the GridView is designed to work.
Does anyone have any suggestions on how to do this or a better alternative?
I also thought about using a hidden field, but I can't add it to the RadioButtonList so it won't help unless it's global. The problem with it being global is that I can't set the value uniquely to the record that has it's RadioButtonList being altered.
Clear as mud? Please ask if you need any clarification.
Thanks in advance!
Just thought I would add an answer and explain how I solved my issue.
Since the scope was too narrow, I needed to add a custom field to the radiobuttonlist. I just went ahead and added the following code:
MyRadioButtonList.Attributes.Add("NecessaryField")
I added this so that everytime a grid view row was databound this code would aldo execute, ensuring that every RadioButtonList had this field.
After that it's available for use.
I'm using an ObjectDataSource and a FormView.
In the FormView I have a set of controls. When the FormView is in edition, I have in particular a ComboBox and a TextBox which are related as follows:
when the ComboBox takes some special values, the TextBox must be read only or not.
For the moment I get that behaviour as follows: the ComboBox triggers a postback when its selected item is changed and in the 'OnPreRender' of my page I get the value of the ComboBox and update the Readonly property of the TextBox accordingly.
What I don't like with this method is that I don't use my object model which is consumed by the ObjectDataSource. The problem is simply that when the FormView is in edition there does not seem to be a way to get the instance of the object which is being edited. The 'DataItem' is null and I haven't found any way to automatically build a new object from the values in the controls to pass it to my business layer. Of course I could do the whole job myself by getting explicitly all the values in the controls, but that's not nice.
Has anybody ever met such a scenario ? Any ideas on how to get a clean design ?
How about using DataItemIndex or DataKey? I would probably use DataKey and then use the business method to look up for the object for the key.
I have a Gridview in which no rows populated initially. means i am not setting any datasource to gridview.I have to populate gridview by adding footerrow.I have given visibility of footerrow as true.So one error is coming as 'Object not set to an instance of an object'.what may be the reason for this? Can anybody help?
Actually i need to add data into the Gridview through the FooterRow.After inserting a few records,i need to insert this data into the database.So, i want this Gridview only to insert data into the database.For a particular "FileID", i have many records,thats why i am using Gridview.Is there any other method for this?
See this question: How to insert a Row in GridView.
The object reference error is probably because you have set no datasource for the GridView. In such cases, the Gridview will not render.
Edit:
I have already linked to another question which provides a very useful link to accomplish the type of functionality you desire. Since you appear not to have found it, here is the relevant link - How to easily insert row in GridView with SqlDataSource?
The article shows how you can use the EmptyDataTemplate of the GridView to enable record insertion using a GridView. Note that you will have to modify the logic a little to insert a group of records in one go, rather than one at a time.
If you have a problem with this solution, please clarify via comments.
Well i have a gridview where i have defined the columns on my own and turned autogenerating off but now i have the problem that i cant access GridView.SelectedRow.DataItem.
As it turns out to be null now, when it had a value when auto generation was turned on..
Edit:
What i need is a way to save the ID of the row while not showing the ID to the user so if there is any way to do this?
I'm guessing DataItem is only properly filled when you are using DataBinding.
Are you using DataBinding?
Ok from this url:
The GridView (and actually, all our
data controls) does not save data
items across postbacks. This reduces
ViewState (if the objects are even
serializable) and enables garbage
collection to happen and clean up your
objects. So, when you click the
button to post back, the GridView has
not called DataBind and therefore your
data item isn't there. This is what
you've discovered.
Guessing you're reading the value from a postback, might just be the problem.
Try using SelectedValue, if you've setup the (primary) key for the items.
I've always used that and it worked.
msdn about SelectedValue
You can create a new hidden template column that will have a label with the ID . and in the cs file you use .FindControl on the rows.
You also have DataKeys property on the gridview, witch I think also does what you want