ModalPopupExtender inside a GridView ItemTemplate - asp.net

How do I use a GridView TemplateField containing a LinkButton that is to display the modal on click? I have rows of data that I want to update the details of when clicking the 'Edit' LinkButton in that row. There is a bunch of data I need to load via codebehind just before the Modal displays.
I was trying the following, but I can't do Modal1.Show() in the event handler because it's in a TemplateField:
<ItemTemplate>
<asp:Button runat="server" ID="HiddenForModal" style="display: none" />
<ajaxToolkit:ModalPopupExtender ID="Modal1" runat="server" TargetControlID="HiddenForModal" PopupControlID="pnlModal" />
<asp:LinkButton ID="btnEdit" runat="server" Text="Edit" onclick="btnEdit_Click" />
<asp:LinkButton ID="btnDelete" runat="server" Text="Delete"></asp:LinkButton>
</ItemTemplate>
Thanks,
Mark

The key is knowing which row in the GridView was the LinkButton that was clicked. You can do this several ways but the way I implemented it is to capture it in the RowCommand event. Then you can access the ModalPopupExtender in the clicked row via FindControl(..).
Page:
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button1" runat="server" style="Display:none;" Text="Button" />
<cc1:ModalPopupExtender ID="ModalPopupExtender1" PopupControlID="Popup1" TargetControlID="Button1" BackgroundCssClass="modalBackground" runat="server" />
<asp:LinkButton ID="LinkButton1" CommandName="Popup" runat="server">Popup</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
Codebehind:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton LinkButton1 = (LinkButton)e.Row.FindControl("LinkButton1");
LinkButton1.CommandArgument = e.Row.RowIndex.ToString();
}
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Popup" && e.CommandArgument != null)
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
ModalPopupExtender modalPopupExtender1 = (ModalPopupExtender)GridView1.Rows[rowIndex].FindControl("ModalPopupExtender1");
modalPopupExtender1.Show();
//Perform any specific processing.
Label1.Text = string.Format("Row # {0}", rowIndex);
}
}
Additionally, because you are opening the modal on a postback anyways you don't actually need the ModalPopupExtender (or the hidden button) in the ItemTemplate. You can move that out and put it on the page (by your popup div) and can simply call the Show() method.
Page:
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" CommandName="Popup" runat="server">Popup</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
Codebehind:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Popup" && e.CommandArgument != null)
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
ModalPopupExtender1.Show();
//Perform any specific processing
Label1.Text = string.Format("<Br>Row # {0}", rowIndex);
}
}
Thanks, good luck!

Related

Gridview.row.count show zero whenever button is click

i have a gridview ,whenever user will click on row of gridview view ,
record will be populated in the textbox ,but i am getting error as
index was out of range. must be non-negative and less than the size of
the collection
also i check gridview.row.count is showing zero.
please help below is my code
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" ShowHeader="false" AllowPaging="false" AllowSorting="false" ToolTip="Click Here To Edit"
Style="table-layout: fixed;" OnRowDataBound="GridView1_RowDataBound"
CssClass="mGrid" PagerStyle-CssClass="pgr" DataKeyNames="AcheadID"
AlternatingRowStyle-CssClass="alt" Width="100%" Height="100%" >
<AlternatingRowStyle CssClass="alt" />
<Columns>
<asp:TemplateField ItemStyle-Width="40px">
<ItemTemplate>
<%#Container.DataItemIndex+1 %>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Account Head ID" DataField="AcheadID" HeaderStyle-HorizontalAlign="Left" Visible="false" />
<asp:TemplateField HeaderText="Account Head" HeaderStyle-HorizontalAlign="Left" ItemStyle-Width="400px">
<ItemTemplate>
<asp:Label ID="lblac_head" runat="server" Text='<%# Bind("ac_head") %>'></asp:Label>
<asp:HiddenField ID="hndacheadID" runat="server" Value='<%# Bind("AcheadID") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="btnTest" runat="server" OnClick="GridView1_OnClick" style="display:none;" />
my codebehind as
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GetAccountHead();
}
}
protected void GridView1_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HiddenField hndac_headid = (HiddenField)e.Row.FindControl("hndac_headid");
if (hndac_headid.Value != "0")
{
e.Row.Attributes.Add("onmouseover", "this.style.backgroundColor='#d3d3d3'");
e.Row.Attributes.Add("onmouseout", "this.style.backgroundColor=''");
e.Row.Attributes.Add("style", "cursor:pointer;");
//e.Row.Attributes.Add("onclick", "location='patron_detail.aspx?id=" + e.Row.Cells[0].Text + "'");
e.Row.Attributes["OnClick"] = Page.ClientScript.GetPostBackClientHyperlink(btnTest, e.Row.RowIndex.ToString());
}
}
}
protected void GridView1_OnClick(object sender, EventArgs e)
{
Button buttonSender = sender as Button;
int index;
GridViewRow row = null;
if (int.TryParse(Request.Params.Get("__EVENTARGUMENT"), out index))
{
row = GridView1.Rows[index];
Label ac_head = (Label)GridView1.Rows[index].FindControl("lblac_head");
}
Index out of range issue happens because Request.Params.Get("__EVENTARGUMENT") doesn't works for Button ( and addiionally ImageButton ) controls.
The Button controls and ImageButton controls does not call the __doPostBack function. Because of this, the _EVENTARGUMENT ( and _EVENTTARGET as well ) will always be empty.
However, other controls such as CheckBoxes, DropDownLists, LinkButtons uses javascript function __doPostBack to trigger a postback.
Try using a LinkButton
As a second check( can be ignored ), just make sure Data is binded to GridView properly like check the IsPostback conditions etc...
Check your GridView, it has an Id GridView2 but you always referencer GridView1.

Adding buttons in DataRow in DataTable

I have dynamically created DataTable to bind the GridView. I have two buttons, their visibility is set to false. I want when I add a new row on button click I want one of the buttons to be set visibility=true in that new row, and the other one button to stay visibility=false. So the button should be visible only for the row which the user adds, not visible in all rows in DataTable. Here is my code, I don't have any idea how to fix this. Please help
Markup:
<asp:GridView ID="GridView2" runat="server" OnRowDataBound="GridView2_RowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button189" Visible="false" OnClick="Button189_Click" runat="server" Text="odzemi svez vrganj" />
<asp:Button ID="btnTest" Visible="false" runat="server" CommandName="odzemi" CssClass="button2" OnClick="btnTest_Click" Text="-" Width="100px" Font-Bold="True" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind:
protected void Button5_Click(object sender, EventArgs e)
{
MethodForAddFirstRow();
//Here i need somehow to set bnTest to be visible only for this row,other button to stay invisible
}
protected void Button5_Click(object sender, EventArgs e)
{
MethodForAddSecondRow();
//Here I need somehow to set Button189 to be visible only for this row,other button to stay invisible
}
In order to handle events of buttons inside grid you need to use OnRowCommand so you need to update your grid to be like the following
<asp:GridView ID="GridView2" runat="server" OnRowDataBound="GridView2_RowDataBound" onrowcommand="gv_RowCommand">
and make sure that each button has CommandName attribute like the following
<asp:Button ID="Button189" Visible="false" OnClick="Button189_Click" runat="server" Text="odzemi svez vrganj" CommandName="Command1" />
<asp:Button ID="btnTest" Visible="false" runat="server" CommandName="Command2" CssClass="button2" OnClick="btnTest_Click" Text="-" Width="100px" Font-Bold="True" />
then create the following event handler inside the code behind
void gv_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if(e.CommandName=="Command1")
{
}
else if(e.CommandName=="Command2")
{
}
}
In order to access buttons inside the rowcommand event handler you can use the following
GridView customersGridView = (GridView)e.CommandSource;
GridViewRow row = customersGridView.Rows[index];
Button btn = (Button)row.FindControl("Button189");
btn.Visible=false;

Updating GridView row on button click

I have a GridView which contains a Link Button inside a Template Field. The code is shown below:
<asp:GridView ID="gv1" runat="server" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1" onrowediting="gv1_RowEditing"
onrowcommand="gv1_RowCommand">
<Columns>
<asp:BoundField DataField="inDetailsId" HeaderText="inDetailsId"
SortExpression="inDetailsId" />
<asp:BoundField DataField="inUserId" HeaderText="inUserId"
SortExpression="inUserId" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnk1" runat="server" Text='<%# Eval("attDate")%>' CommandName="Edit"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="attstatus" HeaderText="attstatus"
SortExpression="attstatus" />
<asp:BoundField DataField="inAttendanceStatusId"
HeaderText="inAttendanceStatusId" SortExpression="inAttendanceStatusId" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:LearnConnectionString %>"
SelectCommand="SELECT * FROM [attendance]"></asp:SqlDataSource>
<asp:Button ID="Button1" runat="server" Text="Button" />
The code-behind is below:
protected void gv1_RowCommand(object sender, GridViewCommandEventArgs e)
{
gv1.EditIndex = 1;
}
On clicking the Link Button, I am setting GridView Edit Index to 1 to make the row editable.
Now I want to save the updated row. On Click of another button on the Web Page, I want to save the updated changes and change the row edit mode to non-editable mode.
The best way to do this is using the specifics events, this way:
protected void gridview1_RowEditing(object sender, GridViewEditEventArgs e)
{
gridview1.EditIndex = e.NewEditIndex;
BindGrid();
}
protected void gridview1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
gridview1.EditIndex = -1;
BindGrid();
}
To save use the event RowUpdating:
protected void gridview1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
GridViewRow row = gridview1.Rows[e.RowIndex];
int id = Convert.ToInt32(gridview1.DataKeys[e.RowIndex].Value);
string name = ((DropDownList)(row.Cells[2].Controls[1])).SelectedValue;
//call save method of your business layer
gridview1.EditIndex = -1;
BindGrid();
}
Remember to declare the event in the gridview markup.

How to get server-control id that in GridView?

I'm trying to access server control that locate inside GridView, but I dont have idea how to do that..
Here is my try:
<asp:GridView ....
.....
<Columns>
<asp:TemplateField>
...
..
<EditItemTemplate>
<asp:TextBox ID="txtName"runat="server" Text='<%# Bind("Name") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="edit" ItemStyle-CssClass="td"
HeaderStyle-CssClass="listtitle">
<ItemTemplate>
<asp:ImageButton ID="btnEdit" runat="server" CommandName="Edit"
AlternateText="edit" ImageUrl="~/css/images/edit-icon.png" />
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="btnUpdate" runat="server" CommandName="Update" Text="Save"
OnClientClick="javascript:return isValid('<%= txtName.ClientID%>')" /> |
<asp:LinkButton ID="btnCancel" runat="server"
CommandName="Cancel" Text="Cancel" />
</EditItemTemplate>
</asp:TemplateField>
...
..
</Columns>
.....
....
</asp:GridView>
The problem is in here
OnClientClick="javascript:return isValid('<%= txtName.ClientID%>')"
When it gets to the isValid function I see the string "<%= txtName.ClientID%>" and not the actual controller id as I should..
So the question is how can I send the id to the JS script?
ibrams answer would have been correct if it was the fields are on ItemTemplate. But this won't work when you are on EditItemTemplate one have to check the RowState also. The condition will be something like this
if ((e.Row.RowState == (DataControlRowState.Edit | DataControlRowState.Alternate)) || (e.Row.RowState == DataControlRowState.Edit))
{
//logic here
}
But a shorter solution will be checking this condition GridView1.EditIndex == e.Row.RowIndex
The snippet should be this.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow && GridView1.EditIndex == e.Row.RowIndex)
{
TextBox txt = (TextBox)e.Row.FindControl("txtName");
LinkButton btn = (LinkButton)e.Row.FindControl("btnUpdate");
string script = String.Format("javascript:return isValid('{0}')", btn.ClientID);
btn.Attributes.Add("onclick", script);
}
}
On RowDataBound event you need to read the client id of your txtName and set the OnClientClick of your linkbutton.
void myGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TextBox txt = (TextBox)e.Row.FindControl("txtName");
Button btn = (LinkButton)e.Row.FindControl("btnUpdate");
btn.OnClientClick = String.Format("javascript:return isValid('{0}')", btn.ClientID);
}
}
As you want to validate value of the txtName textBox it's much more better utilize standart asp.net validation controls. If you have some complext validation rules then you can use CustomValidator and specify javascript function for processing validation on client side. Just set the same validatio ngroup value for the validator attached to the txtName control and for the btnUpdate button.

Fetching the id from the first column of GridView

I have a Grid in which I am showing some records in each row. Here's how it is:
Now, my problem is that when I press the view button, I want to fetch the ID from the first column in a session variable so that I can display the same ID on the next page.
For the ItemTemplate of EditButton, I am using this code:
<ItemTemplate>
<asp:LinkButton ID="EditBtn" CssClass="btn green" CommandName="edit" ToolTip="Edit" Text="Edit" runat="server" />
</ItemTemplate>
You could try passing it as command argument:
<ItemTemplate>
<asp:LinkButton
ID="EditBtn"
CssClass="btn green"
CommandName="edit"
CommandArgument='<%# Eval("FirstColumnId") %>'
OnCommand="EditCommand"
ToolTip="Edit"
Text="Edit"
runat="server" />
</ItemTemplate>
and in the code behind:
protected void EditCommand(object sender, GridViewCommandEventArgs e)
{
var id = e.CommandArgument;
// TODO: do something with the id
}
Try this. No changes are required at your aspx
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
Session["UserID"] = ((Label)GridView1.Rows[e.NewEditIndex].FindControl("lb1")).Text.Trim();
}
Other method (Using DataKeyNames - Preferred)
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
Session["UserID"] = GridView1.DataKeys[e.NewEditIndex].Value.ToString();
}

Resources