In ASP.NET Web Forms, when binding data to templated controls like GridView, FormView, DetailsView, and Repeater, you have two primary databinding expressions: Eval() and Bind(). While they look similar in markup, they serve fundamentally different purposes. This article explains the differences, when to use each, and provides practical examples.
Descripción General of Databinding Expressions
ASP.NET Web Forms uses special expressions inside <%# %> delimiters to bind data from a data source to server controls. The three main expressions are:
| Expression | Direction | Uso |
|---|---|---|
Eval("FieldName") | One-way (read-only) | Display data |
Bind("FieldName") | Two-way (read and write) | Display and edit data |
Container.DataItem | One-way (read-only) | Direct access to the data item object |
Eval(): One-Way (Read-Only) Databinding
Eval() is a one-way databinding method. It retrieves a value from the current data item and displays it in the control. The data flows in only one direction: from the data source to the page.
Basic Syntax
<asp:Label ID="lblName" runat="server" Text='<%# Eval("CustomerName") %>' />
How Eval Works Internally
Eval() is a method of the Page class (technically TemplateControl). Under the hood, it:
- Retrieves the current
DataItemfrom the binding container. - Uses reflection to find the property or field with the specified name.
- Returns the value as an object, which is then converted to a string for display.
Because it uses reflection, Eval() has a slight performance overhead compared to directly casting Container.DataItem. However, for most applications this overhead is negligible.
Formatting with Eval
Eval() supports an optional format string parameter:
<%-- Format as currency --%>
<asp:Label runat="server" Text='<%# Eval("Price", "{0:C}") %>' />
<%-- Format as date --%>
<asp:Label runat="server" Text='<%# Eval("OrderDate", "{0:MM/dd/yyyy}") %>' />
<%-- Format as percentage --%>
<asp:Label runat="server" Text='<%# Eval("Discount", "{0:P2}") %>' />
Bind(): Two-Way Databinding
Bind() provides two-way databinding. Like Eval(), it displays data from the data source in the control. But additionally, when the user modifies the value and submits the form, Bind() automatically extracts the new value and makes it available to the data source control (SqlDataSource, ObjectDataSource, etc.) for update and insert operations.
Basic Syntax
<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("CustomerName") %>' />
How Bind Works Internally
Bind() does everything Eval() does, plus additional work:
- Displays the data value in the control (same as Eval).
- Registers the control and field name with the binding container.
- When a postback occurs (update or insert), the framework automatically extracts the value from the control and includes it in the data source control’s parameters dictionary.
This is why Bind() is essential for editable templates. Without Bind(), you would need to manually extract values from controls in code-behind event handlers.
Formatting with Bind
Bind() also supports format strings, but be cautious with non-string types:
<asp:TextBox runat="server" Text='<%# Bind("Price", "{0:F2}") %>' />
When using format strings with Bind() on editable fields, you may need to handle the conversion back from the formatted string to the original data type in the data source events.
Key Differences Between Eval and Bind
| Feature | Eval() | Bind() |
|---|---|---|
| Binding direction | One-way (read-only) | Two-way (read and write) |
| Data extraction on postback | No | Yes (automatic) |
| Where to use | ItemTemplate, display-only fields | EditItemTemplate, InsertItemTemplate |
| Rendimiento | Slightly faster | Slightly more overhead |
| Format string support | Yes | Yes |
| Works with read-only controls | Yes | Yes (but unnecessary) |
| Works with editable controls | Yes (display only) | Yes (display and extract) |
Practical Ejemplos
GridView with Eval and Bind
<asp:GridView ID="gvCustomers" runat="server"
DataSourceID="sqlCustomers"
AutoGenerateColumns="false"
DataKeyNames="CustomerID">
<Columns>
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<%# Eval("CustomerID") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<%# Eval("CustomerName") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtName" runat="server"
Text='<%# Bind("CustomerName") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Email">
<ItemTemplate>
<%# Eval("Email") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtEmail" runat="server"
Text='<%# Bind("Email") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Joined">
<ItemTemplate>
<%# Eval("JoinDate", "{0:MMM dd, yyyy}") %>
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowEditButton="true" />
</Columns>
</asp:GridView>
In this example:
- CustomerID uses
Eval()because it is the primary key and should not be edited. - CustomerName and Email use
Eval()in theItemTemplatefor display andBind()in theEditItemTemplatefor editing. - JoinDate uses
Eval()with a format string and has no edit template because it should not be modified.
When the user clicks “Update,” the SqlDataSource automatically receives the CustomerName and Email values from the bound controls.
FormView with Insert Template
<asp:FormView ID="fvNewCustomer" runat="server"
DataSourceID="sqlCustomers"
DefaultMode="Insert">
<InsertItemTemplate>
<table>
<tr>
<td>Name:</td>
<td>
<asp:TextBox ID="txtName" runat="server"
Text='<%# Bind("CustomerName") %>' />
</td>
</tr>
<tr>
<td>Email:</td>
<td>
<asp:TextBox ID="txtEmail" runat="server"
Text='<%# Bind("Email") %>' />
</td>
</tr>
<tr>
<td colspan="2">
<asp:Button ID="btnInsert" runat="server"
CommandName="Insert" Text="Add Customer" />
</td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>
Here, Bind() is used in the InsertItemTemplate so the data source control can extract the values when the “Add Customer” button is clicked.
Container.DataItem: Direct Access
A third option for databinding is accessing Container.DataItem directly. This avoids the reflection overhead of Eval() but requires you to cast the data item to the correct type:
<%-- Using Eval (reflection-based) --%>
<%# Eval("CustomerName") %>
<%-- Using Container.DataItem (cast-based, faster) --%>
<%# ((DataRowView)Container.DataItem)["CustomerName"] %>
<%-- For strongly-typed data (e.g., a Customer object) --%>
<%# ((Customer)Container.DataItem).CustomerName %>
When to Use Container.DataItem
- When you need maximum performance and are binding a large number of rows.
- When you need to call methods or access properties not directly available through
Eval(). - When working with complex objects that require navigation (e.g.,
Customer.Address.City).
Common Mistakes and Pitfalls
Using Eval in EditItemTemplate
<!-- Wrong: Eval in EditItemTemplate - values will not be sent back -->
<EditItemTemplate>
<asp:TextBox runat="server" Text='<%# Eval("Name") %>' />
</EditItemTemplate>
<!-- Correct: Bind in EditItemTemplate - values are extracted on postback -->
<EditItemTemplate>
<asp:TextBox runat="server" Text='<%# Bind("Name") %>' />
</EditItemTemplate>
If you use Eval() in an edit template, the user can type new values, but the data source control will not receive them. The update will either fail or use the old values.
Mixing Quotes Incorrectly
<!-- Wrong: double quotes inside double quotes -->
<asp:Label runat="server" Text="<%# Eval("Name") %>" />
<!-- Correct: single quotes wrapping the expression -->
<asp:Label runat="server" Text='<%# Eval("Name") %>' />
Using Bind Where Eval Suffices
Using Bind() everywhere adds unnecessary overhead. In read-only templates like ItemTemplate, always use Eval():
<!-- Unnecessary: Bind in a read-only template -->
<ItemTemplate>
<%# Bind("CustomerName") %>
</ItemTemplate>
<!-- Better: Eval in a read-only template -->
<ItemTemplate>
<%# Eval("CustomerName") %>
</ItemTemplate>
Rendimiento Considerations
For most applications, the performance difference between Eval() and Bind() is negligible. However, in scenarios with thousands of rows or frequent postbacks:
- Use
Eval()in all read-only contexts to avoid the two-way binding overhead. - Consider
Container.DataItemwith explicit casting for the best performance. - Use paging in GridView and other controls to limit the number of rows rendered at once.
- Enable
ViewStateonly where needed, asBind()contributes to ViewState size.
Resumen
Eval() and Bind() are the two primary databinding expressions in ASP.NET Web Forms. Use Eval() for one-way, read-only data display in ItemTemplate and other non-editable contexts. Use Bind() for two-way databinding in EditItemTemplate and InsertItemTemplate where user-modified values need to be automatically sent back to the data source control. For direct object access with the best performance, use Container.DataItem with explicit casting. Choosing the right expression for each scenario ensures both correct functionality and optimal performance.