static void

ASP.Net Binding

ADO/Dataset notes - Asp2 quickstart
MSDN: GridView, DetailsVew, SQLDataSource, ObjectDataSource, Asp.net paging with ODS tutorial

Eval/Bind syntax

<%# Container.DataItem("Price") %> ASP1. Format: DataBinder.Eval(Container.DataItem, "Price", "{0:C}")
<%# Eval("Price", "{0:C}") %> ASP2. One way with optional formatting.
Eval == DataBinder.Eval (DataBinder==Container in ASP2)
<%# (((System.Data.DataRowView)Container.DataItem)["Price"]) %> Explcit cast, avoid reflection. To find the actual type (DataRowView here), add a <%# Container.DataItem %>
<%# Bind("Price") %> ASP2. Two way
<%# MyMethod(Container.DataItem) %> Remember this can be useful
<%# Container.DataItemIndex %> The row index. For instance, for a "manual" radio button in a gridView (Request["rPick"] will be the item index):

<input type="radio" name="rPick" id='r<%# Container.DataItemIndex %>' value='<%# Container.DataItemIndex %>' />

ObjectDataSource

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="PersonRecord"
       SelectMethod="FindAll"
       UpdateMethod="Update" DataObjectTypeName="PersonRecord" />
<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1"
       AutoGenerateEditButton="true" />

The ASP ObjectDataSource is pretty limited for normal business objects/POCOs but it's okay for simple ActiveRecord type classes. In practice I use my ObjectAdaptor a lot, and sometimes you just have to downgrade to a dataTable (here's a base EntityDataSource that reflects the object to create a datatable [CodeBetter].

Obviously, there's no filtering unless you use a Dataset (/table/view) and paging and sorting has to be done manually (but fairly simple for a typed dataset).

Gridviews: Getting the Data/Row

From a asp:ButtonField int rowIndex = Convert.ToInt32(e.CommandArgument);
If you template it, you can do the same trick with one of the following:
CommandArgument='<%# ((GridViewRow) Container).RowIndex %>' or
CommandArgument='<%# DataBinder.Eval(Container, "RowIndex") %>' or
(won't work in nested UpdatePanel) CommandArgument='<%# Container.DataItemIndex %>'.

<asp:GridView ID="GridView1" runat="server" AutoGenerateEditButton="True"
    DataKeyNames="Id"
    onrowediting="GridView1_RowEditing" onrowcommand="GridView1_RowCommand" >
    <Columns>
        <asp:ButtonField CommandName="DeleteButton" HeaderText="Delete" Text="Delete" />
        <asp:TemplateField HeaderText="Delete (Template)">
            <ItemTemplate>
                <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="false"
                    CommandName="DeleteTemplate" Text="Delete"
                    CommandArgument='<%# ((GridViewRow)Container).RowIndex %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
    GridView gv = (GridView)sender;
    //for ButtonField e.CommandArgument is the integer rowIndex
    //for templated columns it's not unless CommandArgument bound to ((GridViewRow)Container).RowIndex
    int rowIndex = Convert.ToInt32(e.CommandArgument);
    GridViewRow row = gv.Rows[rowIndex];
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    GridView gv = (GridView)sender;
    int rowIndex = e.NewEditIndex; //AutoGenerateEditButton / CommandName="Edit"
    GridViewRow row = gv.Rows[rowIndex];
    int id = Convert.ToInt32(gv.DataKeys[rowIndex][0]);
}

GridView Events RowIndex/Row Data
RowCommand //if ButtonField or CommandArgument set as above
int rowIndex = Convert.ToInt32(commandArgument);
GridViewRow row = gv.Rows[rowIndex];
gv.DataKeys[rowIndex][0]
RowEditing int rowIndex = e.NewEditIndex;
GridViewRow row = gv.Rows[rowIndex];
RowUpdating int rowIndex = e.RowIndex; //if bound to DataSource
e.Keys[0];e.NewValues["Name"]

Gridviews and DataViews

Bound controls are pretty limited- the fact that DataFormatString will only work if HtmlEncode= false is particularly crap.

<asp:BoundField DataField="Date" HeaderText="Date"
  DataFormatString="{0:dd/MM/yyyy}" HtmlEncode="False" />
<asp:BoundField DataField="Cost" HeaderText="Cost"
  DataFormatString="{0:c}" HtmlEncode="False" />

Practically you have to template most columns (to add the validators). Oh yes, and the CompareValidator still doesn't understand currency symbols if Type="currency". Grrr.
ButtonFields with ButtonType="Image" always post twice. As a button, or a templated field, it's okay. (MS bug- marked "fixed" but it's still in 3.5)

If you're deleting, you'll get paging display bugs in GridView because ObjectDataSource doesn't return AffectedRows (SqlDataSource default paging works, but it loads all the data every time).

protected void DataSourceDeleted(object sender, ObjectDataSourceStatusEventArgs e)
{
    e.AffectedRows = (int)e.ReturnValue;
}

GridView PagerRow

Adding text to the pager, without creating a template.

    //data is datasource; count is total number
    gv.RowCreated += delegate(object sender, GridViewRowEventArgs e)
                        {
                            if (e.Row.RowType == DataControlRowType.Pager)
                                AddPagerText(e.Row, count);
                        };
    gv.DataSource = data;
    gv.DataBind();
}
 
private static void AddPagerText(TableRow row, int count)
{
    Label lab = new Label();
    lab.CssClass = "PagerLabel"; //easy styling
    lab.Text = string.Format("{0} found. Result page: ", count);
 
    Table table = new Table(); //put into table like the page numbers
    TableRow tabrow = new TableRow();
    TableCell cell = new TableCell();
    cell.Controls.Add(lab);
    tabrow.Controls.Add(cell);
    table.Controls.Add(tabrow);
 
    //pager template render one cell containing an HTMLTable
    row.Cells[0].Controls.AddAt(0, table);
}