Bind an ASP.NET DropDownList to SQL Server data (C#)
Filling a drop-down list from a database table is one of the first things every Web Forms developer writes. Three properties do the work: DataSource, DataTextField and DataValueField. The details that make it correct are the placeholder item, binding only once, and validating the choice.
Markup
<asp:Label runat="server" AssociatedControlID="ddlCategory" Text="Category" />
<asp:DropDownList ID="ddlCategory" runat="server" AppendDataBoundItems="true">
<asp:ListItem Value="" Text="-- choose a category --" />
</asp:DropDownList>
<asp:RequiredFieldValidator runat="server" ControlToValidate="ddlCategory" InitialValue=""
ErrorMessage="Please choose a category." Display="Dynamic" />
<asp:Button ID="btnNext" runat="server" Text="Next" OnClick="btnNext_Click" />
AppendDataBoundItems="true" keeps the static placeholder and appends the database rows after it. The validator's InitialValue="" makes the placeholder count as "nothing chosen".
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindCategories();
}
}
private void BindCategories()
{
string cs = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
using (var con = new SqlConnection(cs))
using (var cmd = new SqlCommand("SELECT CategoryId, Name FROM dbo.Categories WHERE Active = 1 ORDER BY Name", con))
{
con.Open();
using (SqlDataReader r = cmd.ExecuteReader())
{
ddlCategory.DataSource = r;
ddlCategory.DataTextField = "Name"; // what the user sees
ddlCategory.DataValueField = "CategoryId"; // what is posted
ddlCategory.DataBind();
}
}
}
protected void btnNext_Click(object sender, EventArgs e)
{
if (!IsValid) return;
int categoryId = int.Parse(ddlCategory.SelectedValue);
string categoryName = ddlCategory.SelectedItem.Text;
// ...
}
Binding inside if (!IsPostBack) matters: the list keeps its items across postbacks through view state, and rebinding in every Page_Load would reset the user's selection before btnNext_Click reads it. If you must rebind (for example after adding a category), call ddlCategory.Items.Clear() first and re-add the placeholder, or the items accumulate because of AppendDataBoundItems.
Binding to a reader works because the list enumerates it once during DataBind, while the connection is still open.
Variations
- Display text built from several columns: select it in SQL (
Name + N' (' + Code + N')' AS Label) and useDataTextField="Label", or useDataTextFormatString="{0} items"for simple formatting of one field. - Declarative binding: a
SqlDataSourcewithDataSourceIDdoes the same without code-behind. - Tooltips per item need a small loop after binding: see DropDownList item tooltips.
- Dependent lists: cascading Country, State and City lists.
Common mistakes
- Swapping
DataTextFieldandDataValueField: the user sees ids and the server receives names. - Forgetting
AppendDataBoundItems="true": the placeholder item disappears on binding. - Rebinding on every postback: the selection is reset before your click handler reads it.
- Reading
SelectedItem.Textwithout checkingSelectedValuefirst: the placeholder text may be saved as data.
Official documentation
- Microsoft Learn: ListControl.DataTextField, ListControl.DataValueField, AppendDataBoundItems
- Microsoft Learn: RequiredFieldValidator.InitialValue