Before anything, I have to say that I do not advocate uncritical use of this solution. A good system should validate all input and keep its entities valid at all times. If you end up needing this one, you shold be needing it because you're creating a quick fix in a legacy system, or you're working with something that _should_ have errors. :)
My particular need just now is that I'm introducing a dropdown for a freetext field in a system I inherited. Its using LINQ to SQL datasources and no business layer what-so-ever, and I'm not about to make on on my 4 hour budget.
Anyway, according to this feedback post, I'm guessing MS isn't gonna bake this into the .net framework anytime soon.
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=260603
So here's an inherited DropDownList that does exactly that. :)
(Pretty quick and easy, so I guess that's why we don't get one in the box)
Note: It iterates over the items in the list one extra time, so it does degrade performance!
public class ForgivingDropDownList : DropDownList
{
[Category("Behavior"), DefaultValue(true)]
public bool AllowInvalidSelectedValue
{
get { return ViewState["allowInvalid"] != null ? (bool)ViewState["allowInvalid"] : true; }
set { ViewState["allowInvalid"] = value; }
}
public override string SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (!AllowInvalidSelectedValue)
{
base.SelectedValue = value;
return;
}
if (this.Items.Count != 0)
{
if ((value == null) || (base.DesignMode && (value.Length == 0)))
{
this.ClearSelection();
return;
}
ListItem item = this.Items.FindByValue(value);
if (item == null)
{
base.SelectedValue = null;
return;
}
base.SelectedValue = value;
}
}
}
}
And here's some simple sample usage:
<asp:FormView ID="FormView1" runat="server">
<EditItemTemplate>
<cc1:ForgivingDropDownList ID="ForgivingDropDownList1" runat="server" SelectedValue='<%# Bind("Text") %>'>
<asp:ListItem>a</asp:ListItem>
<asp:ListItem>b</asp:ListItem>
</cc1:ForgivingDropDownList>
</EditItemTemplate>
</asp:FormView>
public class Thing
{
public string Text { get; set; }
}
public partial class ForgivingDropDownPage : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e )
{
if (!IsPostBack)
{
FormView1.DefaultMode = FormViewMode.Edit;
FormView1.DataSource = new Thing[] { new Thing { Text = "c" } };
FormView1.DataBind();
}
}
}
And that's it. :) Enjoy!