I am having an issue with my web forms datagrid responding to a click event. Allow me to explain:
When the user selects an item in the dropdownlist, a datagrid (called tmdg) appears (2nd page load) with ButtonColumns in it. When the user selects a button in one of the ButtonColumns in the datagrid, the value of the button flips from false to true (or from true to false, depending on its starting value). In the Page_Load event, if Page.IsPostBack==true, i assign an event handler to the datagrid (tmdg) like so: tmdg.ItemCommand += Tmdg_ItemCommand;
Tmdg_ItemCommand is the method that calls Save() which flips the datatable and ultimately the datagrid cell value.
This all works for the VERY FIRST click in the datagrid. HOWEVER, for subsequent clicking of the datagrid, the button.DataTextField values only flip on the SECOND click of the grid. (essentially a "double click" instead of a single click). My goal is to flip the value of the cell in the ButtonColumn for every single click event.
Please note: after the first click of the grid where the value flips succesfully, if I may click cell (5,6) where nothing happens, if then i click cell (7,2) I will get a flip of that cell (7,2). Likewise, I could just click (5,2) again where nothing happens, then select (5,2) again to get the flip. (this is what i mean by essentially a "double click")
Other notes:
I have tried assigning the event handler ALL OVER the application in mulitple spots (before Page_Load in OnInit of the page; or in the UpdatePanel's Panel_Init method; or regardless of if Page.IsPostBack in Page_Load; or after Page_Load)
The datagrid is a dynamically loaded control that is placed on a Panel which, in turn, is placed on an UpdatePanel.
I will try not to place a huge mess of code here, but do want to provide you with SOMETHING. I have redacted it a bit for the sake of brevity.
::::Push.aspx::::
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Push.aspx.cs" Inherits="TMUWF.Push" MasterPageFile="~/Site.Master" %>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:DropDownList ID="DropDownList1"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
runat="server"
AutoPostBack="True"
AppendDataBoundItems="true"
OnMouseDown="this.size=10;"
OnFocusOut="this.size=1;"
OnDblClick="this.size=1;"
>
</asp:DropDownList>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" OnInit="Panel_Init">
<contenttemplate>
<h3 id="div-Col-Title">Node</h3>
<asp:Panel runat="server" ID="Panel1">
<div id="div-Row-Title"><h3 >Channel</h3></div>
</asp:Panel>
</contenttemplate>
</asp:UpdatePanel>
</asp:Content>
::::Push.aspx.cs::::
namespace TMUWF
{
public partial class Push : System.Web.UI.Page
{
DataGrid tmdg = new DataGrid
{
AutoGenerateColumns = false,
CssClass = "gvClass push"
};
DataTable TraffMat = new DataTable();
DataView TraffMatView;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
UpdatePanel1.Visible = false;
FillDropDown();
}
else if (!(Session["PushIntId"] == null))
{
int IntID = GetSession();
BindGrid(IntID);
// instead of checking for null, just remove the event handler
tmdg.ItemCommand -= Tmdg_ItemCommand;
// Manually register the event-handling method for the item click
tmdg.ItemCommand += Tmdg_ItemCommand;
}
}
private void FillDropDown()
{ //redacted, pulls values from database for dropdownlist
}
private void BindGrid(int IntID)
{
if (Panel1.Controls.Contains(tmdg))
{
Panel1.Controls.Remove(tmdg);
}
SaveSession(IntID);
tmdg = BuildTmdg(tmdg, TraffMat);
TraffMatView = new DataView(TraffMat);
// Set the data source and bind to the Data Grid control.
tmdg.DataSource = TraffMatView;
tmdg.DataBind();
if (!Panel1.Controls.Contains(tmdg))
{
Panel1.Controls.Add(tmdg);
}
UpdatePanel1.Visible = true;
UpdatePanel1.Update();
}
private DataGrid BuildTmdg(DataGrid dg, DataTable dt)
{
dg.Columns.Clear();
for (int col = 0; col<17; col++)
{
if (col == 0)
{
BoundColumn bc = new BoundColumn
{
HeaderText = " ",
DataField = dt.Columns[col].ToString(),
ReadOnly = true
};
dg.Columns.Add(bc);
}
else
{
ButtonColumn btnc = new ButtonColumn
{
HeaderText = col.ToString(),
ButtonType = ButtonColumnType.PushButton,
DataTextField = dt.Columns[col].ToString(),
CommandName = col.ToString()
};
dg.Columns.Add(btnc);
}
}
return dg;
}
private void Tmdg_ItemCommand(object source, DataGridCommandEventArgs e)
{
Save((Int32)Session["PushIntID"], Convert.ToInt32(e.CommandName), e.Item.DataSetIndex+1);
}
private void Save(int IntID, int col, int row)
{
int newIntID = IntID;
int newcol = col;
int newrow = row;
// Apply changes to DataTable
string newVal = UpdateDataTable(IntID, col, row);
// Apply changes to Database
int rowsAffected = Apply(IntID, col, row, newVal);
// Bind DataTable to TMDG
BindGrid(IntID);
}
private string UpdateDataTable(int IntID, int col, int row)
{
row--;
string val = TraffMat.Rows[row][col].ToString();
if (val == "False")
{
val = "True";
TraffMat.Rows[row][col] = val;
}
else
{
val = "False";
TraffMat.Rows[row][col] = val;
}
TraffMat.AcceptChanges();
SaveSession(IntID);
TraffMatView = new DataView(TraffMat);
return val;
}
private int Apply(int IntID, int col, int row, string NewVal)
{ //redacted, saves values to database
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{ //redacted, fills DataTable from database, calls SaveSession, calls BindGrid
}
private int GetSession()
{ //redacted, gets session state
}
private void SaveSession(int IntID)
{ //redacted, sets session state
}
}
}
As it appears to me, when i set a breakpoint inside both "if" statements in BindGrid() the first "if" is often skipped implying that Panel1 does not contain my datagrid tmdg at that moment in time. This "if" is specifically skipped in that "first-click" that is ignored.
Please let me know if you need any more information from me! I hope that one of you can figure out what i'm doing improperly!! Any and all comments appreciated..
Instead of instantiating the datagrid tmdg in Push.aspx.cs, I added it to Push.aspx and the click event fires every time. I'm not sure why this works in .aspx but doesn't in the .aspx.cs file.
New code follows to explain...
::::Push.aspx:::: (datagrid added here)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Push.aspx.cs" Inherits="TMUWF.Push" MasterPageFile="~/Site.Master" %>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:DropDownList ID="DropDownList1"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
runat="server"
AutoPostBack="True"
AppendDataBoundItems="true"
OnMouseDown="this.size=10;"
OnFocusOut="this.size=1;"
OnDblClick="this.size=1;"
>
</asp:DropDownList>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" OnInit="Panel_Init">
<contenttemplate>
<h3 id="div-Col-Title">Node</h3>
<asp:Panel runat="server" ID="Panel1">
<div id="div-Row-Title"><h3 >Channel</h3></div>
<asp:DataGrid ID="tmdg" CssClass="gvClass push" AutoGenerateColumns="false" runat="server" >
</asp:DataGrid>
</asp:Panel>
</contenttemplate>
</asp:UpdatePanel>
</asp:Content>
::::Push.aspx.cs:::: (datagrid removed here)
//DataGrid tmdg = new DataGrid
//{
// AutoGenerateColumns = false,
// CssClass = "gvClass push"
//};
Thoughts on WHY appreciated.