You might have wanted to use inside a databound templated server control (e.g. the
FormView or the GridView) several cascading dropdownlists. The System.Web.UI.WebControls.ListItems
in each dropdownlist would change based on the selection of the previous dropdownlist,
e.g. the city selections would change based on the province and the latter would
change based on the country selection. Sounds easy? Well, you added to your webform
a datasource object linked for each dropdownlist where the SelectParameters collection
contains a ControlParameter pointing to the previous list.
But you encounter any of those 2 error messages:
- Databinding methods such as Eval(), XPath(), and Bind() can only be used in the
context of a databound control
- 'DropDownList1' has a SelectedValue which is invalid because it does not exist in
the list of items.
The problem is that you are attempting to bind to a dependent dropdown list a value
from its container’s data context when it was not bound to the container. The container
is the FormView or GridView in this demo. Its data context is the address record
that you are attempting to Edit or Insert.
In this example, a change in the country dropdown list selection causes the datasource
for the province’s list to retrieve a list of provinces specific to that country
selection. This does not cause a problem. The problem appears when you have a BIND
statement that attempts to bind the selectedvalue of the province dropdown list
to a property on the address object, e.g. SelectedValue='<%#Bind("provinceId")
%>'. However the postback (triggered by the country's selection change)
did not re-bind the container (the FormView or the GridView) to its data context (the address
object) rather the container's template was rendered from the saved viewstate. Therefore
you get the error that informs you that you cannot use BIND on a control that is
not databound to its data context.
There are two ways to deal with the problem; you can either try a technical workaround
to remove the 2-way databinding from the cascading dropdownlists and replace it
with customized code during processing the ItemUpdating event as I did in this demo,
or you can change the way you look at the data in a cascading relationship, which
I present in this ASP.NET
3.5 demo.
The sample demo that Microsoft presented in its AJAX Toolkit CascadingDropDown sample used a case where
the color for a particular car make-model does not necessarily have to be a unique
data record, i.e. the green color record is not unique to Acura-Integra, it can
also be a color selection for Audi-A6. Therefore a car's record saves all three
values (car make, model and color). The 3 keys represent a unique identifier to
be able to retrieve the cascading relationship that the user specified. But if we
were to change this relationship such as the green color record for Acura-Integra
has an Id that is different from the green color record for Audi-A6 then we do not
need to save the user selection of the car make and model. We can use the color
record selection to identify both the car make and model.
In this demo I deal with a case where you are able to save all values of the cascading
relationship on the same record by handling the ItemUpdating and ItemInserting events
instead of using the 2-way databinding method BIND. But in this
ASP.NET 3.5 ListView demo I present the strategy that allows you to save
the cascading relationship by saving only the id of the record at the lowest level
of the cascading relationhsip (in this case it is the CityId)
If you are still getting the message that:
'DropDownList1' has a SelectedValue which is invalid because it does not exist in
the list of items.
then since you are using Bind (which will set the selected value from the data as
well as save the selected value to data upon update), the dropdownlist must be populated
with all possible values.
The solutions are
- if the problem is happening due to Null values in databound field then you can declare
the dropdownlist with a null item at top while setting the AppendDataBoundItems
property to true so that items are appended to (instead of replacing) the null item,
like this
<asp:DropDownList ID="ddlCountry"
runat="server
AppendDataBoundItems=true
DataSourceID="odsCountries" AutoPostBack="True"
SelectedValue='<%# Bind("Country") %>'>
<asp:ListItem Value="">Select an Item</asp:ListItem>
</asp:DropDownList>
For more information on the usage of the AppenDataBoundItems property refer to the
MSDN:
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.listcontrol.appenddatabounditems(VS.80).aspx
- if the problem is happening due to illegal values saved in the databound field (that
are not part of the set of values displayed on the dropdownlist) then you can:
- fix the data on the database
- create a join query within the objectdatasource for dropdownlist that would bring
not only the legal values for this list but also any illegal values in the databound
field
- handle it on the level of the user interface like I did on my sample where I removed
the Bind statement from the DropDownList and replaced with code within the dropdownlist.DataBound
and the
GridViewRowUpdating events