It seems that when adding a row to an ASP.NET GridView, the Tab Index does not behave as expected (or desired). Instead of tabbing across each column in a row and then moving to the next row, the tab will move down each row in a column and then move to the next column and so on. Simply put, it will tab vertically instead of horizontally. This can be an issue for data entry applications where a user relies heavily on keyboard input.
Any solutions for this issue?
I have been screwing with this for a while and have this solution! Hope it helps other people who have the same issue.
protected void theGridView_DataBound(object sender, EventArgs e)
{
SetTabIndexes();
}
private void SetTabIndexes()
{
short currentTabIndex = 0;
inputFieldBeforeGridView.TabIndex = ++currentTabIndex;
foreach (GridViewRow gvr in theGridView.Rows)
{
DropDownList dropDown1 = (DropDownList)gvr.FindControl("dropDown1");
dropDown1.TabIndex = ++currentTabIndex;
TextBox inputField1 = (TextBox)gvr.FindControl("inputField1");
inputField1.TabIndex = ++currentTabIndex;
TextBox inputField2 = (TextBox)gvr.FindControl("inputField2");
inputField2.TabIndex = ++currentTabIndex;
TextBox inputField3 = (TextBox)gvr.FindControl("inputField3");
inputField3.TabIndex = ++currentTabIndex;
}
someLinkAfterGridView.TabIndex = ++currentTabIndex;
}
Have a look at Automatically create TabIndex in a repeater
For each control you could set the TabIndex to a property in code behind.
<asp:GridView ID="gv" runat="server">
<columns>
<asp:TemplateField HeaderText="Action" ShowHeader="False" Visible="true">
<ItemTemplate>
<asp:CheckBox ID="cbGroup" Checked="true" runat="server" TabIndex='<%# TabIndex %>' Text='<%# Eval("Title") %>' />
</ItemTemplate>
</asp:TemplateField>
</columns>
</asp:GridVeiw>
Then in code behind increment a TabIndex counter:
private int _tabIndex = 0;
public int TabIndex
{
get
{
_tabIndex++;
return _tabIndex;
}
}
You could assign the TabIndex's for all your controls inside the grid manually on the rowdatabound event. Figure out how many controls you want to tab though on a specific row and then based on the row index just formulate the tab order.
Related
I have two check boxes with the GridView TemplateField. I want to uncheck the checked boxes after submission. My gridview
<asp:GridView ID="GridView1" runat="server" HorizontalAlign="Center" DataKeyNames="ShiftID"
Width="177px" onrowdatabound="GridView1_RowDataBound1">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="ChbGrid" runat="server"
oncheckedchanged="ChbGrid_CheckedChanged" />
</ItemTemplate>
<HeaderTemplate>
<asp:CheckBox ID="ChbGridHead" runat="server" AutoPostBack="True"
Font-Bold="True" oncheckedchanged="ChbGridHead_CheckedChanged" />
</HeaderTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I tried in below mentioned methode
public void checkboxclear()
{
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox chkrow = (CheckBox)row.FindControl("ChbGrid");
if(chkrow.Checked==true)
{
chkrow.Checked = false;//it works
}
else
{
CheckBox chkrow1 = (CheckBox)row.FindControl("ChbGridHead");
if (chkrow1.Checked == true)
{
chkrow1.Checked = false;//it shows error like "Object reference not set to instance of an object"
}
}
}
How can I improve my code to solve this issue? Why I am unable to call these check boxes inside the aspx.cs page
You need to check for the RowType becuase your second checkbox is in the HeaderTemplate. For that gridview generates special HeaderRow. That you can directly access and set the value to it.
public void checkboxclear()
{
foreach (GridViewRow row in GridView1.Rows)
{
if(row.RowType == DataControlRowType.DataRow)
{
CheckBox chkrow = (CheckBox)row.FindControl("ChbGrid");
if(chkrow.Checked)
chkrow.Checked = false;
}
}
CheckBox chkrow1 = (CheckBox)GridView1.HeaderRow.FindControl("ChbGridHead");
if (chkrow1.Checked)
chkrow1.Checked = false;
}
Also you don't need to use the chkrow.Checked==true. chkrow.Checked it returns boolean value so that direactly should check in if condition.
I guess I don't know when you are calling this function, but the correct place to pre-set values is in the row databound event.
Having said that the reason your code is blowing up is that you are looking for the header check box in every row, and it is only in the header row. Just access the header through the gridviews header property and do your find control there.
https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.headerrow(v=vs.110).aspx
Something like
CheckBox chkHeader = (CheckBox)Gridview1.HeaderRow.FindControl("ChbGridHead");
I am confused with this problem.
I have put a button in side the template field of a gridview and want to return the data from that specific GridView Row when that corresponding button is clicked.
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button2" CssClass ="btnSkin" runat="server" Text="Answer" Width="117px" onclick="Button2_Click" />
</ItemTemplate>
</asp:TemplateField>
In the button click event fireup, I want to read that data by creating a GridViewRow Element.
protected void Button2_Click(object sender, EventArgs e)
{
GridViewRow gvr = (GridViewRow)(sender as Control).Parent.Parent;
Label8.Text = gvr.Cells[1].Text;
Label10.Text = gvr.Cells[2].Text;
Label12.Text = gvr.Cells[3].Text;
}
Now the problem is, the GridViewRow Cells are returning empty strings.
What should I do?????
When using <asp:TemplateFields>, you actually need to find the text which is inside your controls such as <asp:Label> you used inside your <ItemTemplate>.
Cells won't have text, its the Controls inside the cells that have text.
So, If suppose , you have a Label inside one of your <ItemTemplate> as:
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("CustomerID") %>'>
</asp:Label>
</ItemTemplate>
Then access the Text of this Label control using below code in your button Click event:[ assuming, 2nd Column contains the above <ItemTemplate> defined ]
protected void Button2_Click(object sender, EventArgs e)
{
GridViewRow gvr = (GridViewRow)(sender as Control).Parent.Parent;
String str = ((Label)gvr.Cells[1].FindControl("Label1")).Text;
}
I found the reason behind the empty strings error.
Gridview.Cells[i].Text will return the string value only when it is a <asp:BoundField>
If it is a <asp:TemplateField> and you have some ASP control inside the <ItemTemplate>, you must follow the FindControl("<control_id>") approach.
Here, basically we look for the control object in that particular GridviewRow Cell by its ID and cast it into the corresponding Control Type. Now, we can use that as we call any other asp control from code-behind.
String str = ((Label)gvr.Cells[1].FindControl("Label1")).Text;
Try using GridView.RowCommand Event and refer the following link for the same
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand.aspx
hope this helps you.
Please check whether you are binding the grid properly on Page Load.
if(!IsPostBack)
{
BindgridView();
}
Hope this helps..Give a try..
I have two textbox and one gridview in my webform. The gridview is binded with database. But I want to add one more column on runtime which will be the textbox input from the webform. Because the scenario is like: I am maintaining two formula to calculate some percentage using the two textbox and the client wants to see this calculation for each row in the gridview.
But I cannot do this.
Is there anyone who can help me on this please? May be some suggestion.
Thanks in advance.
You could add the column in your GridView markup with a label control to display the result as follows.
Here is the markup needed, please note Visible is set to false.
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField Visible="false">
<ItemTemplate>
<asp:Label ID="label1" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Use the RowDataBound event to find the label and calculate your result as below:
void GridView1GridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
//find the control
var label1 = e.Item.FindControl("label1") as Label;
if (label1 != null)
{
if (!string.IsNullOrEmpty(tbInput1.Text) && !string.IsNullOrEmpty(tbInput2.Text))
{
// Do the calculation and set the label
label1.Text = tbInput1.Text + tbInput2.Text;
// Make the column visible
GridView1.Columns[0].Visible = true;
}
}
}
}
Please forgive any errors, I have not tested the above.
On an ASP.NET page, I have a gridview which contains a dropdownlist in one of its columns. While other columns in the gridview are databound, the dropdown list is NOT, and only contains 3 preset values "Frank", "Yes", and "No". ("Frank" is used as an example so that I don't get false readings from my preferred blank option)
<asp:GridView ID="testGrid" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Code1" HeaderText="Code1" />
<asp:BoundField DataField="Code2" HeaderText="Code2" />
<asp:TemplateField HeaderText="Like Frank?">
<ItemTemplate>
<asp:DropDownList runat="server" ID="ddlLikeFrank">
<asp:ListItem>Frank</asp:ListItem>
<asp:ListItem>Yes</asp:ListItem>
<asp:ListItem>No</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
<asp:HyperLinkField ... HeaderText="File" />
</Columns>
</asp:GridView>
<br />
<asp:Button ID="cmdUpdate" runat="server" Text="Update" OnClick="cmdUpdate_Click" /></div>
I don't need AutoPostBack on these dropdownlists, as I only want to consider their selected values when the button cmdUpdate is clicked.
protected void cmdUpdate_Click(object sender, EventArgs e)
{
bool likesFrank = false;
string selected = "";
DropDownList ddl = null;
GridViewRow current = null;
// Go through each row and check the dropdown list.
for (int i = 0; i < testGrid.Rows.Count; i++)
{
current = testGrid.Rows[i];
...
ddl = (DropDownList)(current.FindControl("ddlLikeFrank"));
/* THIS FOR LOOP IS WAS USED FOR INVESTIGATING THIS ISSUE*/
for (int j = 0; j < ddl.Items.Count; j++)
{
if (ddl.Items[j].Selected)
{
continue;
}
}
selected = ddl.SelectedItem.Value;
switch (selected)
{
case LIKE: // "Yes"
likesFrank = true;
break;
case DONT_LIKE: // "No"
likesFrank = false;
break;
default: // If nothing is selected in the drop-down list, move on.
continue;
} // end switch block
/* USE THE DERIVED BOOLS HERE */
} // end for loop on grid rows
} // end method cmdUpdateClick
The problem is this: No matter what item is selected in any of the dropdownlists, my page thinks that every single one of them is set to "Frank", i.e. the first item. Moreover, if I put a breakpoint on the top of the for loop denoted as the "Investigation code", and then interact with the page as follows:
Select different dropdownlist options for different rows.
Click the Update button.
... my debugging code tells me that none of the items are selected! Not one of them!! I can be looking at 2 Yes's and 3 No's on the page, and my debug tools in VS2008 are telling me that every single dropdownlist has nothing selected.
How can this be possible? (NOTE: I have tried this with EnableViewState set to true, and with EnableViewState not even mentioned in the page header.)
Thanks.
take a hit with this. Replace index based for with this
foreach(GridViewRow row in grid.Rows)
{
var ddlVal = ((DropDownList)row.FindControl("yourId")).SelectedItem.Value;
}
<< use SelectedItem.Value - I think this will solve your problem >>
Update:
To update the selected index of the ddl you needto do a postback. Enable autopostback=true. But here , you have mentioned you do not want autopostback, since this isthe only workaround, so place the gridview in an updatepanel to suppress postback
At server side
protected void btnSaveRankChanges_Click(object sender, EventArgs e)
{
foreach (GridViewRow grv in GridViewRankChanges.Rows)
{
DropDownList dropDownChangeRank = (DropDownList)grv.FindControl("DropDownListRank");
StudentInfoObject.RankID = Convert.ToInt32(dropDownChangeRank.SelectedValue);
}
}
in grid
<asp:TemplateField HeaderText="Select New Rank">
<ItemTemplate>
<asp:DropDownList ID="DropDownListRank" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
On button click
<asp:Button ID="btnSaveRankChanges" runat="server" Text="Submit" ValidationGroup="RankChanges"
class="accordionHeader" Height="27px" OnClick="btnSaveRankChanges_Click" OnClientClick="LoadImage()" />
Dropdown binds in this way
/// <summary>
/// bind dropdown with rank in grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void GridViewRankChanges_RowDataBound(object sender, GridViewRowEventArgs e)
{
DropDownList drdList;
// Nested DropDownList Control reference is passed to the DrdList object. This will allow you access the properties of dropdownlist placed inside the GridView Template column.
if (e.Row.RowType == DataControlRowType.DataRow)
{
//bind dropdown rank
drdList = (DropDownList)e.Row.FindControl("DropDownListRank");
drdList.DataSource = RankList.GetRankList(false);
drdList.DataTextField = "Rank";
drdList.DataValueField = "RankID";
drdList.DataBind();
drdList.Items.Insert(0, new ListItem("Select", "0"));
}
}
It works for me hope it helps for you too.
I think you are rebinding the grid on every post back, which will reload the entire data along with dropdowns. For ex. Please check if(!page.IsPostBack) before doing databiniding of gridview.
Please let me know if this is not the issue.
I want to make the gridview.columns[0] as hyperlink. I tried so many work around mentioned in different sites. I am binding a list<> to the grid. and I need to make the first column as hyperlink and upon clicking that link, it should be redirected to a page with the corresponding item.
Which event I need to use and how can I pass that value from the list?
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var firstCell = e.Row.Cells[0];
firstCell.Controls.Clear();
firstCell.Controls.Add(new HyperLink { NavigateUrl = firstCell.Text, Text = firstCell.Text });
}
}
Be warned that if you bind data to grid only first time page loaded then your changes will disappear.
You have to make that column as Template Column
<asp:TemplateField HeaderText="">
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" Text="test" NavigateUrl='<%# Eval("fieldName", "show.aspx?ID={0}") %>'></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>