Reputation: 2608
'ddlUser' has a SelectedValue which is invalid because it does not exist in the list of items. Parameter name: value
This is the Errormessage i get, when I call the following Code:
ASPX:
<asp:FormView ID="FormView1" runat="server" DataSourceID="EntityDataSource1">
<EditItemTemplate>
<asp:DropDownList runat="server" ID="ddlUser" Selectedvalue='<%# Bind("UserID") %>'
AppendDataBoundItems="true" DataSourceID="EntityDataSource2"
DataTextField="UserName" DataValueField="UserID" >
<asp:ListItem></asp:ListItem>
</asp:DropDownList>
<asp:EntityDataSource ID="EntityDataSource2" runat="server" EntitySetName="User" AutoGenerateWhereClause="true">
<WhereParameters>
<asp:Parameter Name="deleted" DefaultValue="false" Type="Boolean" />
</WhereParameters>
</asp:EntityDataSource>
The reason for this issue is, that EntityDataSource2
only selects not deleted users. BUT selected users can be deleted any time and then they appear no longer in the result, which leads to this error.
I've searched for answers and only fond this one, which works but produces duplicate entries (because DataBind
is called twice). Another discussion here without result.
Question: How can I prevent this error and select the empty item if the user was deleted in the meantime.
What i've tried so far:
First I thought of
protected void DropDownList1_DataBinding(object sender, EventArgs e)
{
DropDownList DropDownList1 = (DropDownList)sender;
if(!Helper.CheckIfValid(DropDownList1.SelectedValue))
{
DropDownList1.SelectedValue = "";
}
}
but the SelectedValue
is not set at DataBinding
event.
Upvotes: 1
Views: 274
Reputation: 3475
This is a work around suggestion. I think this is not a clean solution but hope it could help.
The reason for this issue is that the selected item does not exist in the list of items. To prevent it happens, we should ensure that the selected item will always exist by doing as following.
We add an item that has the same value as selected value.
<asp:DropDownList runat="server" ID="ddlUser" Selectedvalue='<%# Bind("UserID") %>'
AppendDataBoundItems="true" DataSourceID="EntityDataSource2"
DataTextField="UserName" DataValueField="UserID"
OnDataBound="OnListDataBound" >
<asp:ListItem Value="">(none)</asp:ListItem>
<asp:ListItem Value='<%# Bind("UserID") %>'></asp:ListItem>
</asp:DropDownList>
Then on DataBound event, we do addition check to find out weither the selected value is valid or not.
protected void OnListDataBound(object sender, EventArgs e)
{
// addition check
}
UPDATE
After revising the problem, seem I've been thinking too complicated. My above suggestion is also a bad solution.
Obviously, it's not valid to select an item that doesn't exist in the list. So instead trying to bind a value that could be invalid, why don't we remove it, and then select the correct value in code behind?
ASPX
<asp:DropDownList runat="server" ID="ddlUser"
AppendDataBoundItems="true" DataSourceID="EntityDataSource2"
DataTextField="UserName" DataValueField="UserID"
OnDataBound="OnListDataBound" >
<asp:ListItem Value="">(none)</asp:ListItem>
</asp:DropDownList>
Code-behind
protected void OnListDataBound(object sender, EventArgs e)
{
DropDownList dropdown = (DropDownList)sender;
string userId = string.Empty;
// Assign value for userId from FormView1.DataSource
....
// Check to select valid item
ListItem foundItem = dropdown.Items.FindByValue(userId);
if (foundItem != null)
{
dropdown.SelectedValue = userId;
}
else
{
dropdown.SelectedValue = string.Empty;
}
}
Upvotes: 0
Reputation: 139256
I suggest you define a custom control in your project (and reference it instead of asp:DropDownList
) derived from the standard DrowDownList
that will not throw when the selection is not defined as an item in the list.
If should work as is (by default, the empty value item will be selected), but you can also define what you consider as the value or the text that represent the "not selected" item using one of its properties. Here is the class:
public class ExtendedDropDownList : System.Web.UI.WebControls.DropDownList
{
protected override void PerformDataBinding(IEnumerable dataSource)
{
try
{
base.PerformDataBinding(dataSource);
}
catch (ArgumentOutOfRangeException)
{
ListItem item;
// try the value we defined as the one that represents <no selection>
if (NoSelectionValue != null)
{
item = Items.FindByValue(NoSelectionValue);
if (item != null)
{
item.Selected = true;
return;
}
}
// try the text we defined as the one that represents <no selection>
if (NoSelectionText != null)
{
item = Items.FindByText(NoSelectionText);
if (item != null)
{
item.Selected = true;
return;
}
}
// try the empty value if it exists
item = Items.FindByValue(string.Empty);
if (item != null)
{
item.Selected = true;
return;
}
}
}
[DefaultValue(null)]
public string NoSelectionValue
{
get
{
return (string)ViewState[nameof(NoSelectionValue)];
}
set
{
ViewState[nameof(NoSelectionValue)] = value;
}
}
[DefaultValue(null)]
public string NoSelectionText
{
get
{
return (string)ViewState[nameof(NoSelectionText)];
}
set
{
ViewState[nameof(NoSelectionText)] = value;
}
}
}
}
Upvotes: 1