I have a LinkButton inside a GridView (via an TemplateField). No matter what I try, the LinkButton will not invoke its event handler. I have tried both:
A traditional event handler ("OnClick")
A OnRowCommand event handler at the GridView level.
In both cases, I've debugged and it doesn't even catch the event handler.
If I move the LinkButton out on the page (so it's not in the GridView), it works fine, so I know the syntax is right.
Here is the "traditional" method:
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" OnClick="CancelThis" runat="server" />
</ItemTemplate>
<asp:TemplateField>
What's interesting is if I remove the "CancelThis" method from the code behind, it throws an error. So I know it's aware of its event handler, because it looks for it when it compiles.
Here is the RowCommand method:
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" CommandName="CancelThis" runat="server" />
</ItemTemplate>
<asp:TemplateField>
In this case, the GridView has:
OnRowCommand="GridView_RowCommand"
It postsback, but never hints at raising the event.
Any idea what I'm missing here?
How are you binding your GridView? Are you using a datasource control? If you are binding manually during Page_Load, it's possible that since the grid is binding every round trip, the event handler isn't catching properly. If this is the case, you may want to try something like:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
//do binding
}
}
Can you post sample binding code to go with your markup?
If you really want to force the issue, you could hook into the RowDataBound event on the Grid, find the button manually and add the handler in the code behind. Something like:
markup snippet:
<asp:GridView ID="gvTest" runat="server" OnRowDataBound="gvTest_RowDataBound" />
code behind:
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
//find button in this row
LinkButton button = e.Row.FindControl("DeleteButton") as button;
if(button != null)
{
button.Click += new EventHandler("DeleteButton_Click");
}
}
}
protected void DeleteButton_Click(object sender, EventArgs e)
{
LinkButton button = (LinkButton)sender;
// do as needed based on button.
}
I'm not sure what the purpose of the button is, but assuming it is a row delete button, you may not want to take this approach as in the event handler, you don't have direct access to the row in question, like you would using the RowCommand event.
Is there a reason you're using the Template field? Vs say a ButtonField? If you use a ButtonField, then you can hook into the RowCommand event.
markup snippet:
<asp:GridView ID="gvTest" runat="server" OnRowCommand="gvTest_RowCommand">
<columns>
<asp:buttonfield buttontype="Link" commandname="Delete" text="Delete"/>
....
</columns>
</asp:GridView>
code behind:
protected void gvTest_RowCommand(object sender, GridViewCommandEventArgs e)
{
if(e.CommandName == "Delete")
{
//take action as needed on this row, for example
int rowIndex = Convert.ToInt32(e.CommandArgument);
GridViewRow currentRow = (sender as GridView).Rows[rowIndex];
//do something against the row...
}
}
You might want to consult MSDN docs on some of these topics:
RowCommandEvent
ButtonField class
EDIT:
To answer your question on the ButtonField - yes I don't see why you couldn't still deal with a buttonfield. Here's a snippet to find the buttonfield during row data bound and hide it (untested but I think would work...)
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//let's assume your buttonfield is in column 1
// (you'd know this based on your markup...)
DataControlFieldCell cell = e.Row.Cells[1] as DataControlFieldCell;
if(cell != null)
{
ButtonField field = cell.ContainingField as ButtonField;
//based on your criteria, show or hide the button
field.Visible = false;
//or
field.Visible = true;
}
}
}
Is viewstate turned on on your GridView? This has caught me out numerous times.
<button onclick="window.open('<%#Eval("ReportLinks")%>', '_blank');" title='<%#Eval("ReportLinks")%>'> Link</button>
Related
I am working on a project where I am creating a dashboard for the Admin.
I have a UsersGridView which displays the data of the registered users in it.
Using the Template field for the Gridview I have created a button for that allows the Admin to with Lockout or Enable the user's to use the system.
<asp:TemplateField HeaderText="LockoutStatus">
<ItemTemplate>
<asp:Button ID="LockoutStatus" runat="server" CausesValidation="false" CommandName="LockoutStatus" Text="Enabled"
CommandArgument='<%# Eval("Id") %>' />
</ItemTemplate>
</asp:TemplateField>
In the RowCommand event how can I change the button CssClass and text if the user is locked out from the system.
There are several ways you can change the CssClass.
With the RowDataBound event.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is d datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//cast the row back to a datarowview
DataRowView row = e.Row.DataItem as DataRowView;
//use findcontrol to locate the butotn
Button btn = e.Row.FindControl("LockoutStatus") as Button;
//change the class based on a column value
if (row["ColumnName"].ToString() == "LockedOut")
{
btn.CssClass = "ClassA";
}
}
}
Or on the aspx page with a ternary operator.
<asp:Button ID="LockoutStatus" runat="server"
CssClass='<%# Eval("ColumnName").ToString() == "LockedOut" ? "ClassA" : "ClassB" %>'
Or as you wanted in the RowCommand event. You can use the CommandSource and cast it to a Button.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
Button btn = e.CommandSource as Button;
btn.CssClass = "ClassA";
}
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="lbShowGroup" CommandName="View" CommandArgument='<%# Eval("Topic") %>'
runat="server" Text="View"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
Code behind:
protected void tblTopics_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "View")
{
Response.Redirect("Group.aspx?Topic=" + e.CommandArgument.ToString());
}
}
Debugging doesn't reach the RowCommand event, but when I change the button control to LinkButton, it works. What's wrong?
Do you databind your grid on postbacks?
You must not bind your grid on postbacks in Page_Load, only when something has changed that causes the GridView to reload data(f.e. Sorting,Paging) and only in the appropriate even-handlers.
So wrap the databinding in a PostBack-check:
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
DataBindGrid();
}
}
Another possible reason: Have you disabled ViewState somewhere?
I had the same issue and found out that my problem was in the Master Page where EnableViewState="false".
I changed the Master page to use EnableViewState="True".
And the rowcommand event fired as expected.
I have a LinkButton in aspx page.
<asp:TextBox ID="textBoxNote" runat="server" />
<asp:LinkButton ID="linkButtonUpdateNote" Text="Update" OnClick="ButtonUpdateNoteClicked" runat="server" />
the click event handler has the following code
protected void ButtonUpdateNoteClicked(object sender, EventArgs e)
{
var note = textBoxNote.Text;
}
On Postback textBoxNote.Text is empty. I don't get the posted value. How to get the value?
It seems like you are possibly resetting the value in your Page_Load.
Check that you are using IsPostback check in the Page_Load function. see - http://msdn.microsoft.com/en-us/library/system.web.ui.page.ispostback.aspx
private void Page_Load()
{
if (!IsPostBack)
{
DoThisOnce();
}
DoThisOnEachPostback();
}
I have a legacy asp.net 3.5 application. I need to bind a filed to CssClass so that i can utilize it via jquery.
Basically, in the datagrid, there are 2 buttons. Button one is visible and button two is not visible. On click of button one, i want to perform action and then make button two visible and hide button one. How can i do this? I just need a kick in the right direction...
<asp:LinkButton ID="lnkDelete" runat="server"
ToolTip="Delete Order <%# DataBinder.Eval(Container.DataItem, "TransID")%>"
OnClientClick="return DeleteOrder();"
OnClick="OrderDelete" CommandArgument='<%# Eval("TransID")'
CssClass="">
<asp:Image ID="Image1" runat="server" ImageUrl="~/images/icons/delete.gif"
BorderStyle="None" />
</asp:LinkButton>
My current binding inside the tooltip results in an error, "the server tag is not well formed".
On the code behind OrderDelete, i can disable the delete link, but how can i make the other button visible?
//delete indivisual order
protected void OrderDelete(object sender, EventArgs e)
{
string transactionID = String.Empty;
LinkButton lnkDelete = (LinkButton)sender;
if (lnkDelete != null)
transactionID = lnkDelete.CommandArgument;
if (!String.IsNullOrEmpty(transactionID))
{
//do delete
}
//refresh results
}
For the server tag not well-formed error, try something like this:
ToolTip='<%# String.Format("Delete Order {0}", DataBinder.Eval(Container.DataItem, "TransID")%>'
For the second part of your question, a little more of your code might help to give you a more specific answer, but in lieu of that, if you know which row of the DataGrid you're in, you should be able to do a FindControl in that row for the second button and make it visible.
Update
You might try setting the tooltip in the codebehind, using the RowDataBound event. Something like this:
protected void gv1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton btn = e.Row.FindContorl("lnkDelete") as LinkButton;
// You'll need to retrieve the values you want to dynamically populate
// the ToolTip with from other controls in the row;
// I don't know if you'd be able to use the DataSource or not, but you might.
btn.ToolTip = "Delete Order ";
}
}
I have nested repeaters on my aspx page.In the outer repeater I am displaying a list of products and in the inner repeater I am displaying a list of additional options associated with each product.The inner repeater contains a checkbox,textbox,label and other stuff.I would like to find the controls inside the outer repeater when a user selects a checkbox in the inner repeater.In order to handle this I am using the following code.
<asp:Repeater ID="OuterRepeater" runat="server"
onitemdatabound="OuterRepeater_ItemDataBound" >
<ItemTemplate>
<asp:Label ID="CodeLabel" runat="server" Text='<%# Eval("Code") %>'></asp:Label>
<asp:Repeater ID="InnerRepeater" runat="server" OnItemCreated="InnerRepeater_ItemCreated">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true"/>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
......
.......
</ItemTemplate>
</asp:Repeater>
......
......
</ItemTemplate>
</asp:Repeater>
protected void InnerRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
RepeaterItem ri = (RepeaterItem)e.Item;
if (ri.ItemType == ListItemType.Item || ri.ItemType == ListItemType.AlternatingItem
)
{
CheckBox cb = ri.FindControl("CheckBox1") as CheckBox;
cb.CheckedChanged += new EventHandler(CheckBox1_CheckedChanged);
}
}
private void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
if (cb.Checked)
{
//do something
}
else
{
//do something
}
}
But the checkedChanged event of the checkbox is not firing for some reason.Also I am not sure how to access the textbox of the outer repeater in the checked changed event of the innter repeater checkbox control.
Could someone please help me with this?
Thanks
It does not fire the CheckedChanged event, since you have declared the event handler as private, You have to make it Protected or Public
Protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
You can access the Textbox control like..
private void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
Textbox textbox1 = (TextBox)checkBox.Parent.FindControl("TextBox1");
String textboxText = textbox1.Text;
}
It doesn't look like you defined an event handler in your markup.
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true" OnCheckedChanged="CheckBox1_CheckedChanged" />
Muhammad Akhtar's answer helped me a lot today!
I just needed to set a specific ID to my dynamic generated checkboxes inside my reapeater to recover the origin of the event, and do the rest of the processing, and it worked perfectly.
chkAtivo.ID = DataBinder.Eval(e.Item.DataItem, "id").ToString();
Reovered just as the sample.
Cant vote up yet, but thank you.