I want to obtain the new value of a cell in the gridview rowUpdating event:
roles.RoleName = gvRoles.Rows[e.RowIndex].Cells[GetColumnIndexByName(row, "RoleName")].Text;
But the value is empty.
I have checked e.NewValues which is an ordered Dictionary. It contains the new changed value. How do I retrieve the new values for update?
aspx design is:
<asp:GridView ID="gvRoles" DataKeyNames="RoleId" runat="server"
AutoGenerateColumns="False" GridLines="Vertical" CssClass="table
table-striped table-bordered" AutoGenerateEditButton="True"
OnRowCancelingEdit="gvRoles_RowCancelingEdit" OnRowUpdating="gvRoles_RowUpdating"
OnRowEditing="gvRoles_RowEditing">
<Columns>
<asp:BoundField DataField="RoleId" HeaderText="RoleId" ReadOnly="True" />
<asp:BoundField DataField="RoleName" HeaderText="RoleName" ReadOnly="false" />
<asp:BoundField DataField="Role_Description" HeaderText="Role Description" ReadOnly="false" />
<asp:TemplateField HeaderText="RoleStatus">
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" SelectedValue='<%# Bind("Role_Status") %>' >
<asp:ListItem>True</asp:ListItem>
<asp:ListItem>False</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblRoleStatus" runat="server"
Text='<%# Bind("Role_Status") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
The easiest way which i found out is to discovered e.NewValues. As I mentioned above it is an ordered dictionary and only i need to manage it.
I need to retrieve new values from this dictionary, which is done i this way.
if (!string.IsNullOrEmpty(e.NewValues["RoleName"].ToString()))
{
roles.RoleName = e.NewValues["RoleName"].ToString();
}
if you have template field it also work for it;
if (!string.IsNullOrEmpty(e.NewValues["Role_Status"].ToString()))
{
roles.Role_Status = Convert.ToBoolean(e.NewValues["Role_Status"].ToString());
}
This is the easiest thing I ever discovered. before that i want just using Find control and casting and then retrieving all lot code.
There is also e.OldValues ordered dictionary. Every one can use it to compare the new value with old ones. If values are same they could notify user to change the value(give new cell value).
GridViewRow row = (GridViewRow)gvRoles.Rows[e.RowIndex];
TextBox textRName = (TextBox)row.Cells[1].Controls[0];
string rname=textRname.Text;
Try This:
protected void gvRoles_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
GridViewRow row = gvRoles.Rows[e.RowIndex];
TextBox txtBox= (TextBox)(row.Cells[1].Controls[0]);
if(txtBox!=null)
{
String str = txtBox.Text;
}
}
After searching long and hard I found a great article that solved my issue. Take a look at the page load if you are binding on post back then the values get updated before you are able to access them.
Follow this link for more details --> https://taditdash.wordpress.com/2014/06/30/why-gridview-rowupdating-event-is-not-giving-the-updated-values/
The return data type ICollection is a bit tricky. Would have preferred a different data type than a string array but this was simplest direct conversion.
// grabs column headers
String[] keyStrings = new string[e.NewValues.Count];
System.Collections.ICollection keys = e.NewValues.Keys;
keys.CopyTo(keyStrings, 0);
// grabs edit row values
String[] valuesStrings = new string[e.NewValues.Count];
System.Collections.ICollection values = e.NewValues.Values;
values.CopyTo(valuesStrings, 0);
The end result here has two string arrays values and keys which can then be indexed, where the column header has the same index value as the cell value of the edited row.
Related
I want to select Particular Cell value and will use to Bind Controls But i am Not able to select Cell Value
Its not retrieving data
ASPX Code
<asp:GridView ID="grdLogedUserDetails" OnRowDeleting="grdLogedUserDetails_RowDeleting" OnRowDataBound="grdLogedUserDetails_RowDataBound"
runat="server" Style="width: 100%; text-align: center" OnRowCommand="grdLogedUserDetails_RowCommand"
class="table table-striped table-bordered" AutoGenerateColumns="false" datakeynames="Ref_ID">
<Columns>
<asp:TemplateField HeaderText="Process No">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Bind("Ref_ID") %>' ID="lblRef_ID"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Company">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Bind("CompanyName") %>' ID="lblCompanyName"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Division">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Bind("DivisionName") %>' ID="lblDivisionName"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:ImageButton ID="imgDel" runat="server" ImageUrl="~/Images/delete.png" AlternateText="Delete" CommandName="Delete" />
</ItemTemplate>
<ItemStyle Width="100px" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:ImageButton ID="imgSel" runat="server" ImageUrl="~/Images/edit-icon.png" AlternateText="Select" CommandName="Select" />
</ItemTemplate>
<ItemStyle Width="100px" />
</asp:TemplateField>
C#
protected void grdLogedUserDetails_RowCommand(object sender, GridViewCommandEventArgs e)
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
//Reference the GridView Row.
GridViewRow row = grdLogedUserDetails.Rows[rowIndex];
//Access Cell values.
int RefID= int.Parse(row.Cells[0].Text);
string Company= row.Cells[1].Text;
string Division= row.Cells[2].Text;
}
protected void grdLogedUserDetails_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Access Cell values.
var RefId = int.Parse(e.Row.Cells[0].Text); // Error Input string is not in correct Formate
string Comany= e.Row.Cells[1].Text;
string Division= e.Row.Cells[2].Text;
}
}
While Debugging I can see Error Like :
"Input string is not in correct Format" Where i am doing wrong
My Table Structure
________________________________________
Ref_ID| CompanyName | DivisionName |
______|_______________|_________________|
6 | Company | Sales |
8 | Company | Sales |
14 | Company | Sales |
______|_______________|_________________|
RefID i have taken as "int" and CompanyName and DivisionName "string" so where i my input string is in wrong format,
Where i am doing wrong Please suggest me on same
The rowcommand event does not trigger rowindexed change unless you have Command="Select" but you DO HAVE Command="Select". However, you don't have a CommandArugment.
However, since you do have command=Select, then move your code to SelectedIndexChanged. The issue is you can't get/grab the row from the "row" command event since the row has not changed. The rowcommand event fires before SelectedIndexChanged. And as noted, unless you use a special command (delete or select) then SelectedIndexChanged does NOT fire.
So rowindex will NOT have been set in the row command event. However, this will mean that for your select button (and delete) your code will be (can be) in rowindexchanged "if" you use say select (or "delete") for the command. if you use a custom command name, then rowindexedchanged does NOT fire.
You can continue to use rowcommand, but you need the CommandArugment to pass either the PK of the row, or the index of the row.
So you have two choices here. (actually 3).
You can set the value of CommandArugment of that button.
Either to the PK, or you can use this
CommandArgument ='<%# Container.DataItemIndex%>'
I note that in your command settings, you are NOT setting the CommandArugment - you have to set it in your markup. The above expression will return the index into the grid.
You can move your code to rowindexchanged.
However, there is a 3rd choice. You CAN GET the rowindex in rowcommand. So from the depths of hell, you can use this stunning whopper insane of a statement:
If e.CommandName = "MySelect" Then
' now get row.
Dim gvRow As GridViewRow = CType(CType(e.CommandSource, Control).NamingContainer, GridViewRow)
Debug.Print("row index = " & gvRow.DataItemIndex)
Dim MyLabel As Label = gvRow.FindControl("HotelName")
Debug.Print("Value ref id = " & MyLabel.Text)
End If
Note VERY careful:
For the templated fields - we use find control. For non tempalted fields, then you can reference by cell.
Now that super award winning ugly way to get the row in row command?
In C# it will look like this:
{
GridViewRow gvRow = (GridViewRow)(Control)e.CommandSource.NamingContainer;
}
So, you have to use above, or as noted, move your code to SelectedIndexChanged.
Since you only have a select and delete button, then I would suggest SelectedIndexChanged. But if you were to say introduce another button - then you would not want to use Select or Delete, but a custom command name of your choosing (say CommandName="MyViewer"). In that case, then SelectedIndexChanged will not fire. But then you would have a means to determine which button was clicked upon (beyond the need of select and delete commands).
So in summary:
You have about 3+ ways to do this.
Keep in mind that in row command, the selected index event has NOT yet fired.
Keep in mind that if you use a custom row command name, then selected index WILL NOT fire.
Keep in mind that you can pick up the selected row with that award winning ugly line of code.
Keep in mind that you can't use cells() collection for your custom templated columns - so use find control.
Keep in mind that selectedindex in row command event has NOT changed nor fired yet.
Since you ARE using select, then you have a choice of row command event, or selectedindex changed event - they will both fire in your case.
The problem is that the cell does not contain any text, but a Label lblRef_ID. So you need to access the label, not the cell value.
var label = e.Row.FindControl("lblRef_ID") as Label;
var RefId = int.Parse(label.Text);
My question is how can i insert values into gridviews rows.Basically I have created a gridview in which i bound the footer and i want to insert values in the footer.I have create a 'textboxs','dropdownlist' and 'checkboxes'.I want when i insert value and press "Insert" button then values shown in the gridview and again i insert value and press button then show inserted values in the gridview.Here is my gridview image
and i also want to edit and delete rows as well.Here is my code :
aspx code
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
Height="104px" ShowFooter="True" Width="463px"
AutoGenerateDeleteButton="True" AutoGenerateEditButton="True">
<Columns>
<asp:TemplateField HeaderText="Column Name">
<FooterTemplate>
<asp:TextBox ID="name" runat="server"></asp:TextBox>
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Data Type">
<FooterTemplate>
<asp:DropDownList ID="DropDownList2" runat="server">
</asp:DropDownList>
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Allow Null">
<FooterTemplate>
<asp:CheckBox ID="allow_null" runat="server" />
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Primary Key">
<FooterTemplate>
<asp:CheckBox ID="primary" runat="server" />
</FooterTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and here is my aspx.cs code :
protected void Button1_Click(object sender, EventArgs e)
{
string name = TextBox1.Text;
string type = DropDownList1.Text;
string allow=Null.Text;
string primary = Primary.Text;
name = ((TextBox)GridView1.FooterRow.FindControl("TextBox2")).Text;
type = ((DropDownList)GridView1.FooterRow.FindControl("DropDownList2")).Text;
allow = ((CheckBox)GridView1.FooterRow.FindControl("allow_null")).Text;
primary = ((CheckBox)GridView1.FooterRow.FindControl("primary")).Text;
}
To use the GridView in this way, with input fields in the footer and a Insert Button that is outside the GridView, you need to make a manual Insert.
I don't know how you perform an Insert using the EF model as I don't currently use it. I guess you could say the "old" way is to use an instance of SqlConnection and SqlCommand. You would use code similar to this inside your Button Click event:
// This is VB. C# is similar, you will have to convert where needed
Using connection As New SqlConnection(connectionString)
Using command As New SqlCommand(queryString, connection)
command.Connection.Open()
command.CommandType = // Typically Text or StoredProcedure as needed
command.Parameters.AddWithValue("#parameter_name1", some_value_1)
command.Parameters.AddWithValue("#parameter_name2", some_value_2)
.
.
.
command.ExecuteNonQuery()
End Using
End Using
queryString is your sql INSERT statement or a stored procedure
command.Parameters is a collection of replaceable parameter in your INSERT statement or Stored Proc.
Addendum
A Gridview is a Data bound control so typically when you use a gridview it's bound to some backing data source. If you are not using a database then you are using some other construct.
If you are using, for example, a DataTable, you would add the new rows and columns to the DataTable using its row and column methods and then rebind the DataTable to the Gridview. You don't add rows and columns directly to a GridView.
See this other SO answer by JonH for an example
In case this helps this is based on the ASPSnippets but modified to be more like you might need. Note that instead of using a DataTable I am using a List where "Row" is a class. It is somewhat a matter of personal preference which one you use. The "Row" class is:
[Serializable]
public class Row
{
public string FieldName { get; set; }
public string FieldType { get; set; }
public Boolean FieldNullible { get; set; }
public Boolean FieldPrimaryKey { get; set; }
}
My names are different from your names. Note that the ASPSnippets sample does not use TemplateFields so I am not. I am not sure if you need to make the "allow"
and/or "primary" fields Boolean so I did not process them in the form. So the ASP.Net form I have is:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
Height="104px" Width="463px"
AutoGenerateDeleteButton="True" AutoGenerateEditButton="True">
<Columns>
<asp:BoundField DataField="FieldName" HeaderText="Name" ItemStyle-Width="120" />
<asp:BoundField DataField="FieldType" HeaderText="Type" ItemStyle-Width="120" />
</Columns>
</asp:GridView>
<br /><asp:Label ID="Label1" runat="server" Text="Name:"></asp:Label>
<br /><asp:TextBox ID="txtName" runat="server" />
<br /><asp:Label ID="Label2" runat="server" Text="Type:"></asp:Label>
<br /><asp:TextBox ID="txtType" runat="server" />
<br /><asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="Insert" />
The code-behind is:
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
return;
List<Row> Rows = new List<Row>();
ViewState["Rows"] = Rows;
BindGrid();
}
protected void BindGrid()
{
GridView1.DataSource = (List<Row>)ViewState["Rows"];
GridView1.DataBind();
}
protected void Insert(object sender, EventArgs e)
{
List<Row> Rows = (List < Row >)ViewState["Rows"];
Row r = new Row();
r.FieldName = txtName.Text.Trim();
r.FieldType = txtType.Text.Trim();
Rows.Add(r);
ViewState["Rows"] = Rows;
BindGrid();
txtName.Text = string.Empty;
txtType.Text = string.Empty;
}
One thing I do not like is that the GridView does not show until there is data in it. I assume you can fix that.
This does not implement the editing and deleting.
I have a GridView with some predefined Columns and some generated in code. The idea is that I show Columns according to category, selected by user. I cannot create all Columns and just hide them because I don't know how many Columns I will need. I manage to generate Columns I needed, but the problem starts when I try to remove generated Columns. Situation looks like this:
On first load I see GridView of all categories.
After clicking in ListBox I get result I want. 1 additional Column is created (RemoveAt is not called, because no additional Columns were yet created.).
After clicking in other ListBox Item I still get result I want. Column created last time where deleted and new Column added.
At this point, if I click any other ListBox Item in LicensesCategoriesListBox_SelectedIndexChanged on debugging I see that all of GridView TemplateFields are empty (http://tinypic.com/r/98vdkm/8).
If I comment section gridView.Columns.RemoveAt(i - 1) everything works fine, just Columns keeps generating and generating. Any ideas why all of my TemplateFields, written in my Page becomes empty?
My Page looks like this:
<asp:ListBox ID="licensesCategoriesListBox" runat="server" AutoPostBack="true" OnSelectedIndexChanged="LicensesCategoriesListBox_SelectedIndexChanged" />
<asp:GridView ID="licencesGridView" runat="server" AutoGenerateColumns="False" Caption="Licencijos" DataKeyNames="id" ShowFooter="True">
<Columns>
<asp:TemplateField HeaderText="Pavadinimas">
<EditItemTemplate>
<asp:TextBox ID="licenceNameTextBox" runat="server" MaxLength="50" Text='<%# Bind("name") %>' />
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox ID="newLicenceNameTextBox" runat="server" MaxLength="50" ToolTip="Pavadinimas" />
</FooterTemplate>
<ItemTemplate>
<span><%# Eval("name") %></span>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Kategorija">
<EditItemTemplate>
<asp:DropDownList ID="licenceCategoryDropDownList" runat="server" />
</EditItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="newLicenceCategoryDropDownList" runat="server" ToolTip="Kategorija">
<asp:ListItem Text="Pasirinkite kategorijÄ…:" />
</asp:DropDownList>
</FooterTemplate>
<ItemTemplate>
<span><%# Eval("category") %></span>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code:
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
FillLicences(ref licencesGridView);
}
}
protected void LicensesCategoriesListBox_SelectedIndexChanged(object sender, EventArgs e) {
FillLicences(ref licencesGridView, licensesCategoriesListBox.SelectedValue); /// Value is ID of category.
}
public void FillLicences(ref GridView gridView, string category = "") {
DataTable dataTable;
ushort categoryId;
if (UInt16.TryParse(category, out categoryId)) {
PutAdditionalColumns(ref gridView, categoryId);
dataTable = sqlCommands.GetLicences(categoryId); /// Returns DataTable [name], [category] and additional fields that I add in PutAdditionalColumns method.
} else {
dataTable = sqlCommands.GetAllLicences(); /// Returns DataTable with only [name], [category]
}
gridView.DataSource = dataTable;
gridView.DataBind();
}
public void PutAdditionalColumns(ref GridView gridView, uint category) {
for (ushort i = (ushort)gridView.Columns.Count; i > 2; i--) { /// Removes columns at the end (created for other category)
gridView.Columns.RemoveAt(i - 1);
}
foreach (var pair in sqlCommands.GetLicencesCategoryAttributes(category)) { /// Takes additional field needed.
TemplateField field = new TemplateField(); /// New empty column.
field.AccessibleHeaderText = pair.Key.ToString();
field.HeaderText = pair.Value;
gridView.Columns.Add(field);
}
}
Any ideas why all of my TemplateFields, written in my Page becomes
empty?
Because each of those fields is considered a Column. You're removing them in the code.
If this is your issue, you need some way to seperate columns defined in the aspx to the ones created in the code.
I'd use DataColumn.ExtendedProperties to do this.
Whenever you add a column from code, add a value to ExtendedProperties, showing that it was created in the code.
//...
TemplateField field = new TemplateField(); /// New empty column.
field.AccessibleHeaderText = pair.Key.ToString();
field.HeaderText = pair.Value;
DataColumn ourNewColumn = gridView.Columns.Add(field);
ourNewColumn.ExtendedProperties.Add("CreatedInCode", true);
//...
And then when you come to delete them, only delete them if they have this property set.
//...
if( gridView.Columns[i - 1].ExtendedProperties.ContainsKey("CreatedInCode") ) {
gridView.Columns.RemoveAt(i - 1);
}
//...
Hi and thanks in advance.
I have a gridview that has four columns. The fourth column is hidden or displayed based on a set of criteria which is working correctly. But when the table displays, the very first cell in that last column is not showing any text, even though on databound it clearly shows that it has the text. So the gridview winds up showing data like this:
Name Address Zip Code
X H. Smith 123 Raton Ave.
X A. Rally 345 6th St 98453
X B. Holcomb 876 Harrison Blvd 56321
The OnRowDataBound looks like this:
protected void gvAddresses_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//This test evaluation string showed the correct data for every row
//string myvalue = DataBinder.Eval(e.Row.DataItem, "ZipCode").ToString();
if (user.State == (int)States.California)
gvAddresses.Columns[3].Visible = true;
}
}
There doesn't seem to be any problem with the binding and when I debug through the gridview each row is processed as I would expect. Here is the gridview:
<asp:GridView runat="server" ID="gvAddresses" CssClass="TableFormat gvMargin" Width="100%" AutoGenerateColumns="false"
OnRowCommand="gvAddresses_OnRowCommand" OnRowDeleting="gvAddresses_OnRowDeleting" OnRowDataBound="gvAddresses_OnRowDataBound">
<EmptyDataTemplate>
<div style="text-align: center;">No addresses available.</div>
</EmptyDataTemplate>
<Columns>
<asp:TemplateField HeaderText="" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:LinkButton ID="lnkRemoveAddress" runat="server" OnClientClick="if(!confirm('Are you sure you want to delete this record?')) return ;" style="color: maroon; font-weight: bold;" Text="X" CommandName="Delete" CommandArgument='<%# Eval("AddressCode") %>'></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="Address" HeaderText="Address" />
<asp:BoundField DataField="ZipCode" HeaderText="Zip Code" Visible="False"/>
</Columns>
</asp:GridView>
How else can I discover what is happening to this first cell?
First problem is this: you are checking every individual row and setting the entire column to visible or not over and again. You should check for State before you databind, since it is the user object I would suggest doing it on preinit.
I suggest you remove the visible=false from your markup. When you set visible to false then the control/object isn't rendered into the HTML. Your problem will most likely be fixed if you remove the visibility attribute from the markup and assign that value at the proper time in codebehind.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
if (!postback)
{
gvAddresses.Columns[3].Visible = User.State == (int)States.California;
}
}
I've searched around and haven't found a solution yet.
I have a Gridview populated by a Stored Procedure that is called by a DropdownList. The query works fine and gives me a table with values. You'll see that I programmed text in the first column to be converted to Hyperlinks.
Everything works fine with the exception that the first row (that's not the Header row) doesn't have a link. In fact, the hyperlink address is applied to the next row instead. And so it bumps the rest of the links down one row.
I did find that when debugging, it seems that the cell in what's supposed to be the first hyperlink comes up with a null ("") value. When I traverse in the IntelliSense, I do find that the row does show the correct properties (there is a text value in the DataItem > Row > ItemArray).
Client Side
<asp:TableCell>
<asp:Label ID="ddlLabel" runat="server" Text="Choose a Group Folder: " />
<asp:DropDownList ID="ddlFolders" runat="server" AutoPostBack="true"
OnSelectedIndexChanged="ddlFolders_SelectedIndexChanged">
</asp:DropDownList>
</asp:TableCell>
<asp:TableCell ColumnSpan="2">
<asp:GridView ID="gvReportList" runat="server" AutoGenerateColumns="false"
CellPadding="5" OnRowDataBound="gvReportList_RowDataBound" Width="98%">
<Columns>
<asp:HyperLinkField HeaderText="Name" DataTextField="Name" Target="_blank" />
<asp:BoundField HeaderText="Description" DataField="Description" />
</Columns>
</asp:GridView>
</asp:TableCell>
Server Side C#
// hyperlink binding by row for first column in gridview
protected void gvReportList_RowDataBound(object sender, GridViewRowEventArgs e)
{
//Changes text in the first column into HyperLinks
HyperLinkField nameLink = gvReportList.Columns[0] as HyperLinkField;
string linkPath = "http://inserted-address-here";
if (e.Row.RowType == DataControlRowType.DataRow)
{
//applies a unique suffix to the address depending on the link name
HyperLink nameHl = (HyperLink)e.Row.Cells[0].Controls[0];
string nameText = nameHl.Text;
string linkSuffix = nameText.Replace(" ", "+");
nameLink.NavigateUrl = linkPath + linkSuffix;
}
}
I can only assume it has something to do with the order in which I'm binding the hyperlinks to the gridview. OR that it has something to do with the first row coming up with a null value even though there's data there.
string linkSuffix = Datainder.Eval(e.DataItem, "Name").ToString().Replace(" ", "+");
nameLink.NavigateUrl = linkPath + linkSuffix;