CheckBox in GridView firing CheckedChanged event at wrong time - asp.net

I have a checkbox in my gridview footer with autopostack=true (which should fire a checkedchanged event), and a linkbutton in my itemtemplate (which should fire the gridview rowcommand event).
Everything has been working fine, until I placed the following code in my gridview rowdatabound (or databound) event:
for (int i = 0; i < gridCartRows.Columns.Count - 2; i++)
{
e.Row.Cells.RemoveAt(0);
}
e.Row.Cells[0].ColumnSpan = gridCartRows.Columns.Count - 1;
Now, when I click my linkbutton, the checkbox checkedchanged event is automatically fired, and then the rowcommand event is fired.
Why is the checkedchanged event being fired when it shouldn't, when I add the above code?
Is there a way to get around this?
Edit
Here's a sample, that reproduces my issue:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" ShowFooter="True"
OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Column1">
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Column2">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" Text="Fire Row Command" CommandName="Fire" />
</ItemTemplate>
<FooterTemplate>
Footer
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true" OnCheckedChanged="CheckBox1_CheckedChanged" />
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Column3">
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code-behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSource = new int[5];
GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
for (int i = 0; i < GridView1.Columns.Count - 2; i++)
{
e.Row.Cells.RemoveAt(0);
}
e.Row.Cells[0].ColumnSpan = GridView1.Columns.Count - 1;
((CheckBox)e.Row.FindControl("CheckBox1")).Checked = true;
}
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Fire")
{
Response.Write("RowCommand fired.");
}
}
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
Response.Write("CheckBox fired.");
}
Note, I'm setting the CheckBox property to true in the RowDataBound - if I remove this, it works fine. So merging the cells and setting the checkbox property aren't working nicely together.

GridView Control events are stored in viewstate and they can get messed up very easily. Here removing a cell causing to bind different event to link button. Although after postback __EVENTTARGET is LinkButton, wrong method is called and wrong control, event arguments are passed.
I would suggest to hide the cell rather than removing it:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[1].ColumnSpan = GridView1.Columns.Count - 1;
e.Row.Cells[0].Visible = false;
((CheckBox)e.Row.FindControl("CheckBox1")).Checked = true;
}
}
This will serve the purpose.

Related

asp gridview button another command

I have a Gridview based on a Acces DB in .aspx
I added +1 column to the grid, which is:
<asp:TemplateField HeaderText="view">
<ItemTemplate>
<asp:LinkButton runat="server" Text="Select" CommandName="Select" CausesValidation="False" id="Button1"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
I have a button outside of the grid: Button2
Could I add a command to Button1, to simulate to click on Button2 as well? Thank you, regards.
Did I get you correctly:
void ContactsGridView_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if(e.CommandName=="Select")
{
MyFunction();
}
}
void Button2_Click(Object sender, EventArgs e)
{
MyFunction();
}
void MyFunction(){
//your code
}

Get value of gridview.selected.row[] with visible property = 'false'

Hi from this field in my gridview, I'd like to pass the id value when the select command field is clicked, but i don't want to have the id field visible so I have the visible property set to false; however, when I pass it on the SelectedIndexChanged event the value is "" yet when the visible property is set to "true" the text value passes fine. What is the correct way to do this?
<asp:BoundField DataField="Project_ID" Visible="false"/>
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
String ProjID = GridView1.SelectedRow.Cells[10].Text;
}
Try this:
.aspx
<asp:Gridview id="GridView1" runat="server" DataKeyNames="Project_ID" />
.cs
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
if(gridView.SelectedDataKey != null)
{
var selectedId = GridView1.SelectedDataKey.Value;
}
}
Here you'll find more info about DataKeys in Gridviews: http://msdn.microsoft.com/de-de/library/system.web.ui.webcontrols.gridview.selecteddatakey(v=vs.110).aspx
I have done something like this in winform maybe can help you. That is what i used
int rowindex = dataGridView1.CurrentRow.Index;
string ProjID= dataGridView1.Rows[rowindex].Cells[10].Value.ToString();
you could use HiddenField inside your gridView ItemTemplate to keep the ID and use it in onrowcommand event, like below:
.aspx
<asp:GridView ID="gridProject" runat="server"
onrowcommand="gridProject_RowCommand">
<Columns>
<ItemTemplate>
<asp:HiddenField ID="hidProjectID" runat="server"
Value='<%# ((DataRowView)Container.DataItem)["Project_ID"] %>' />
<asp:Button ID="btnProject" runat="server" Text="use pro id"
CommandArgument="<%# ((GridViewRow) Container).RowIndex %>"
CommandName="DoSomething"></asp:Button>
</ItemTemplate>
</Columns>
</asp:GridView>
aspx.cs
protected void gridProject_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = 0;
GridViewRow gridRow;
GridView grid = sender as GridView;
try
{
switch (e.CommandName)
{
case "DoSomething":
index = Convert.ToInt32(e.CommandArgument);
row= gridProject.Rows[index];
string Id = ((HiddenField)row.FindControl("hidProjectID")).Value;
//do whatever you want here
break;
// and you can have as many commands as you want here
}
}
catch { //display error }
}

Repeater with Buttons doesn't fire OnItemCommand even when DataBind doesn't happen when IsPostBack is true

I've got an image button in a Repeater, which is in a User Control, and I can't get the OnItemCommand event to fire when I click it. It always gives the error: "... Invalid postback or callback argument. Event validation is enabled using ..."
When I change the image button to a link button, it doesn't give me the error, but it still doesn't fire the OnItemCommand function.
I found some other relevant answers (such as How to process events from Buttons inside Repeaters? And what's this EnableEventValidation thing?) but they all say, "Make sure you're data-binding your repeater inside of a if(!Page.IsPostBack) block." I have done that, but it didn't make a difference.
Here's the markup for the repeater:
<asp:Repeater ID="rptExpenses" OnItemDataBound="rptExpenses_ItemDataBound" OnItemCommand="Button_Command" runat="server" >
<ItemTemplate>
<asp:ImageButton ID="ibDelete" ImageUrl="~/Images/delete.png" CommandName="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
Here's some exerpts from the code-behind
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
rptExpenses.DataSource = ExpenseIds;
rptExpenses.DataBind();
}
}
protected void rptExpenses_ItemDataBound(object sender, RepeaterItemEventArgs e) {
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem)) {
var ibDelete = (ImageButton)e.Item.FindControl("ibDelete");
ibDelete.CommandArgument = e.Item.DataItem.ToString();
}
}
protected void Button_Command(object sender, EventArgs e) {
var btn = (IButtonControl)sender;
switch (btn.CommandName) {
case "Delete":
//delete it
break;
}
}
Try using this code instead:
<asp:Repeater ID="rptExpenses" runat="server">
<ItemTemplate>
<asp:ImageButton ID="ibRemove" ImageUrl="~/Images/delete.png" runat="server"
CommandName="Remove"
CommandArgument='<%# Container.DataItem %>'
OnCommand="ibRemove_Click"/>
</ItemTemplate>
</asp:Repeater>
And this in the code behind:
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
rptExpenses.DataSource = ExpenseIds;
rptExpenses.DataBind();
}
}
protected void ibRemove_Click(object sender, CommandEventArgs e)
{
var btn = (IButtonControl)sender;
switch (btn.CommandName)
{
case "Remove":
//delete it, use btn.CommandArgument to find id to remove
break;
}
}
If you still receive the ... Invalid postback or callback argument. Event validation is enabled using ... error, it most likely means that you are somewhere re-binding the repeater before the ibRemove_Click(...) event is raised.
I found the reason why this was happening in the answer to this question: Why ItemCommand doesn't fired on My Repeater
Turns out that for some reason the Page's DataBind function was invalidating the repeater's controls without passing through the repeater's OnItemDataBound function a second time.

Gridview Row - value and column name

I would like to get name of column which I click and value of this clicked row.
I found very good example but I`m not able to get this data which I want.
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onClick"] = "location.href='view.aspx?id_lekarza=" + DataBinder.Eval(e.Row.DataItem, "Id_lekarza") + " &klikniete=" + "sss" + " '";
}
}
e.Row.RowIndex all the time 0?
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes.Add("onclick", "javascript:alert('" + e.Row.RowIndex + "');");
e.Row.Style.Add("cursor", "pointer");
}
}
In your GridView you can add a template field like below :
<asp:TemplateField ItemStyle-Width="44px" ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Middle"
HeaderStyle-Height="40px" ShowHeader="false">
<ItemTemplate>
<asp:ImageButton ID="btnSelect" runat="server" ImageUrl="~/Images/btnSelect.png"
CommandName="Select" CommandArgument='<%# Eval("ID") %>'/></ItemTemplate>
<HeaderStyle Height="40px"></HeaderStyle>
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="44px"></ItemStyle>
</asp:TemplateField>
And in your C# codebehind You should create the RowCommand event of the Gridview , and access the CommandArgument of that row like following:
protected void GV_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
//You get the ID of that specific row that you have selected :
string ID=e.CommandArgument.ToString();
//Here you write your code ! For example a select query to get that row from database by the ID you have gained in above line of code
}
}

Why is the footer-item not included in Repeater.Items?

I need to get a value from a textbox inside a FooterTemplate in the OnClick event of a button. My first thought was to loop through the items-property on my repeater, but as you can see in this sample, it only includes the actual databound items, not the footer-item.
ASPX:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
Item<br />
</ItemTemplate>
<FooterTemplate>
Footer<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</FooterTemplate>
</asp:Repeater>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
Code-behind.cs:
protected void Page_Load(object sender, EventArgs e)
{
ListItemCollection items = new ListItemCollection();
items.Add("value1");
items.Add("value2");
Repeater1.DataSource = items;
Repeater1.DataBind();
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(Repeater1.Items.Count);
}
This code will only output "2" as the count, so how do I get to reference my textbox inside the footertemplate?
From the MSDN documentation, the Items is simply a set of RepeaterItems based off the DataSource that you are binding to and does not include items in the Header or FooterTemplates.
If you want to reference the textbox, you can get a reference on ItemDataBound event from the repeater where you can test for the footer.
E.g.
private void Repeater_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Footer)
{
TextBox textBox = e.Item.FindControl("TextBox1") as TextBox;
}
}
You can find controls in the repeater. That will give you all the controls in the repeater (RepeaterItems collection). Now you can do something like this:
RepeaterItem footerItem=null;
foreach(Control cnt in Repeater1.Controls)
{
if(cnt.GetType() == typeof(RepeaterItem) && ((RepeaterItem)cnt).ItemType == ListItemType.Footer)
{
footerItem = cnt;
break;
}
}
The footer should be the last child control of the repeater so you can do something like..
RepeaterItem riFooter = Repeater1.Controls[Repeater1.Controls.Count - 1] as RepeaterItem;
if (riFooter != null && riFooter.ItemType == ListItemType.Footer) {
TextBox TextBox1 = riFooter.FindControl("TextBox1") as TextBox;
if (TextBox1 != null) {
TextBox1.Text = "Test";
}
}

Resources