Dynamically dropping grid columns - effect on postbacks - asp.net

I have read a number of threads here on the subject of posting back data from dynamically added datagrid columns. Everything I've read says that since the columns were added after the Init phase, they are not available in the control collection upon Postback and therefore any data posted back by these dynamically added columns is not available and cannot be restored from ViewState unless they are re-created in Page_Init. I have read that as long as the controls are re-added with identical IDS ( i.e IDS should match match posted back control ids), they will be restored from ViewState.
What if I'm not dynamically adding grid columns but rather dropping some grid columns in the code behind. So the ID's of the columns that remmin should match what was in the control collection to begin with so any data posted back should be resotored right but this is not what I'm seeing. SUppos the following is the list of columns in my ASPX page. If in my code behind I drop the "Test" column but check the checkbox in the first column. Upon postback, the checkbox selection is not maintained. I would have expected it to based on what I've read. Can someone correct my understanding on this?
<Columns>
<asp:TemplateColumn headertext="" headerstyle-width="1%" itemstyle-horizontalalign="center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top">
<HeaderTemplate>
<input id="checkAll" type="checkbox" onclick="CheckAllDataGridCheckBoxes('checkboxIsSelected',this.checked)"/>
</HeaderTemplate>
<itemtemplate>
<asp:CheckBox runat="server" id="checkboxIsSelected" checked='false' />
</itemtemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Subject" HeaderStyle-Width="10%" Visible="TRUE" ItemStyle-HorizontalAlign="Center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label id="labelSubjectID" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "SubjectID") %>' />
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Test" HeaderStyle-Width="5%" Visible="TRUE" ItemStyle-HorizontalAlign="Center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label id="labelTestCode" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "TestCode") %>' />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
Added BindGrid() and the event handler buttonApprove_click. The method SetGridColumns is the one that drops grid columns. Have included that too.
private void BindGrid()
{
try
{
SetMasterDetailControlStates(IsPageInDetailsMode());
if (!ValidateArgs())
{
gridBias.Visible = false;
return;
}
foreach (ListItem displayOption in chkboxDisplay.Items)
{
if (displayOption.Selected)
{
if (displayOption.Value == "Highlight") { _showHighlighting = true; }
}
}
/*
<Snipped>...Make procedure call to get dataset
*/
DataSet ds = sp.GetDataSet();
if (sp.RC != (int)ReturnCode.SUCCESS)
{
if ((sp.RC == (int)ReturnCode.NO_RECORDS_RETURNED))
{
labelMessage.Text = "No data found for the specified filter";
}
else if ((sp.RC == (int)ReturnCode.UNHANDLED_EXCEPTION) || (ds == null))
{
labelMessage.Text = sp.ErrorMessage;
}
ds = null;
gridBias.DataSource = ds;
EnableControls(false);
SetGridColumns();
}
else
{
gridBias.TitleText = BuildGridTitleString();
gridBias.FilterText = BuildGridFilterString();
gridBias.EnableRowsPerPageEdit = true;
SetGridColumns();
//Since grid columns are dynamically added and can change between postbacks
//make sure sort column is valid, if not unset
if (gridBias.SortColumn != null && gridBias.SortColumn.Length > 0)
{
bool foundCol = false;
foreach (DataGridColumn dg in gridBias.Columns)
{
if (gridBias.SortColumn == dg.SortExpression)
{
foundCol = true;
break;
}
}
if (!foundCol)
{
gridBias.SortColumn = "";
gridBias.SortOrder = "";
}
}
if (gridBias.SortColumn.Length == 0) gridBias.SortColumn = "TestCode";
if (gridBias.SortOrder.Length == 0) gridBias.SortOrder = "ASC";
if (gridBias.PageIndex.Length != 0 &&
!gridBias.GridViewMode.Equals(CustomDataGrid.GridViewType.SHOWALL.ToString()))
gridBias.CurrentPageIndex = Convert.ToInt32(gridBias.PageIndex);
ds.Tables[0].DefaultView.Sort = gridBias.SortColumn + " " + gridBias.SortOrder;
gridBias.DataSource = ds.Tables[0].DefaultView;
EnableControls(true);
}
gridBias.HideEmptyColumns = true;
ArrayList cols = new ArrayList();
cols.AddRange(_alRecheckColumns);
gridBias.HideEmptyColumnsList = cols;
gridBias.DataBind();
}
catch (Exception ex)
{
CodeLibrary.ErrorHandling.SetLabel("Error(" + CodeLibrary.ErrorHandling.GetMethodName() + ")", ex.Message, labelMessage, true, "ErrorMsg");
}
}
private void SetGridColumns()
{
ArrayList alCols = new ArrayList();
alCols.Add(""); //Checkbox column
alCols.Add("Subject");
ArrayList alColumnsToBeDeleted = new ArrayList();
Boolean boolColExists = false;
foreach (ListItem chart in chkboxChartType.Items)
{
if (chart.Value == "%Bias")
{
if (rblBiasOptions.SelectedValue == "Subject")
{
foreach (DataGridColumn dg in gridBias.Columns)
{
boolColExists = false;
foreach (string gridColumn in alCols)
{
if (dg.HeaderText == gridColumn)
{
boolColExists = true;
break;
}
}
if (!boolColExists)
{
alColumnsToBeDeleted.Add(gridBias.Columns.IndexOf(dg));
}
}
}
}
// Loop thru the array list and delete columns from the grid.
int count = 0;
foreach (int i in alColumnsToBeDeleted)
{
gridBias.Columns.RemoveAt(i - count); //Subtract index by columns already deleted.
count++;
}
}
protected void buttonApprove_Click(object sender, EventArgs e)
{
try
{
CheckPermission(this.ModuleId, this.GetType().BaseType.ToString(), "buttonApprove_Click");
foreach (DataGridItem i in gridBias.Items)
{
//Loop thru each row and determien values to be saved to DB
if (i.ItemType == ListItemType.Item || i.ItemType == ListItemType.AlternatingItem)
{
bool cbSelected = ((CheckBox)i.FindControl("checkboxIsSelected")).Checked;
if (cbSelected)
{
bool IsApproved = true;
string strSubjectID = ((System.Web.UI.WebControls.Label)i.FindControl("labelSubjectID")).Text;
string strTestCode = ((System.Web.UI.WebControls.Label)i.FindControl("labelTestCode")).Text;
string strSampleType = ((System.Web.UI.WebControls.Label)i.FindControl("labelSampleType")).Text;
string strTestCodeAndType = ((System.Web.UI.WebControls.Label)i.FindControl("labelTestCodeAndType")).Text;
if (((System.Web.UI.WebControls.Label)i.FindControl("labelRecheckNeedsApproval")).Text == "1")
IsApproved = true;
else
IsApproved = false;
SaveToDB(strSubjectID, strTestCode, strSampleType, strTestCodeAndType,IsApproved);
}
}
}
BindGrid();
}
catch (Exception exceptionObject)
{
string strExceptionMessage = exceptionObject.Message + "-" + exceptionObject.InnerException.Message;
CodeLibrary.ErrorHandling.SetLabel("", strExceptionMessage, labelMessage, false, "ErrorMsg"); //--- Set label text
}
}

Related

how to get checkbox is check in gridview OnRowEditing

if anyone can help me, I have problems with gridview, when I use OnRowEditing and OnRowDeleting and inside asp: TemplateField, ItemTemplate I am using a checkbox, when checked the checkbox in checkbox.checked value is never true,
below is my C # script
<asp: Button ID = "Button1" runat = "server" BackColor = "# EFF1F1" BorderStyle = "None"
onclick = "Button1_Click" Text = "Submit Work Program" />
<asp: GridView ID = "GV_program" runat = "server" AutoGenerateColumns = "False"
Its DataKeyNames = "KD_BIDANG" Width = "100%" AutoGenerateEditButton = "True"
AutoGenerateDeleteButton = "true" OnRowEditing = "GV_program_RowEditing"
OnRowDeleting = "GV_program_RowDeleting" OnRowDataBound = "GV_kegiatan_RowDataBound"
BackColor = "White" EmptyDataText = "No Data Activity" AllowPaging = "True">
<EmptyDataRowStyle BackColor="#FF9900" />
<Columns> <asp:TemplateField HeaderStyle-Width="20px"> <ItemTemplate>
<asp:CheckBox ID="cbSelect" runat="server" /> </ItemTemplate> </asp:TemplateField>
</ Columns> </ asp: GridView>
C #
protected void Button1_Click (object sender, EventArgs e)
{
foreach (GridViewRow row in GV_program.Rows)
{
if (((CheckBox) row.FindControl ("cbSelect")). Checked)
{
// Delete something (never get here)
}
}
}
take it one step at a time until you get it working......
Try this:
/* put this value at the "class level" */
public static readonly int GRID_VIEW_COLUMN_ORDINAL_chkBoxSELECT = 3; /* Your number may be different, its the ordinal column number. A static readonly or const value makes your code more readable IMHO */
/*Then in your method */
if (null != this.GV_program)
{
Control cntl = null;
foreach (GridViewRow gvr in this.GV_program.Rows)
{
cntl = gvr.Cells[GRID_VIEW_COLUMN_ORDINAL_chkBoxSELECT].FindControl("cbSelect");
CheckBox cbIsApproved = cntl as CheckBox;
if (null != cbIsApproved)
{
bool myValue = cbIsApproved.Checked;
}
}
}
I just ran this code, and it worked for me.
protected void imgbutSave_Click(object sender, ImageClickEventArgs e)
{
if (null != this.gvMain)
{
Control cntl = null;
string finalMsg = string.Empty;
int counter = 0;
StringBuilder sb = new StringBuilder();
foreach (GridViewRow gvr in this.gvMain.Rows)
{
counter++;
cntl = gvr.Cells[GRID_VIEW_COLUMN_ORDINAL_chkBoxIsApproved].FindControl("chkBoxIsApproved");
CheckBox cbIsApproved = cntl as CheckBox;
if (null != cbIsApproved)
{
sb.Append(string.Format("Row '{0}' (chkBoxIsApproved.Checked) = '{1}'", counter, cbIsApproved.Checked) + System.Environment.NewLine);
}
}
finalMsg = sb.ToString();
}
}
and my aspx code
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chkBoxIsApproved" runat="server" Checked='<%#Eval("IsApproved")%>'>
</asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
My StringBuilder had all of the checkboxes on my page, with the correct .Checked value.

I have a gridview control populated from a database! I want to add a button with text property "reserve" at the end of each row of the gridview.

Depending on whichh button is pressed I have to take the excursion_date_id which I will need in the next form!
SO what is best to use - buttonfield property maybe!
here is my code
First it's the Dates.class
public class Dates
{
private int excursionID;
private DateTime startdates;
private double prices;
public int ExcursionID
{
get { return excursionID; }
set { excursionID = value; }
}
public DateTime StartDates
{
get { return startdates; }
set { startdates = value; }
}
public double Prices
{
get { return prices; }
set { prices = value; }
}
public Dates()
{ }
}
}
Then I populate the gridview with the dates from my database
I want to have a button with text property "reserve" at the end of each row of the gridview!
protected void Page_Load(object sender, EventArgs e)
{
string excursionnId = Request.QueryString["ExcursionId"];
Dates date = new Dates();
List<Dates> listDate = new List<Dates>();
listDate = GetDates();
gvDates.DataSource = listDate;
gvDates.DataBind();
}
public List<Dates> GetDates()
{
List<Dates> datesList = new List<Dates>();
string connectionString = "Server=localhost\\SQLEXPRESS;Database=EXCURSIONSDATABASE;Trusted_Connection=true";
string excursionnID = Request.QueryString["ExcursionID"];
string query =
"SELECT Excursion_date_ID, Excursion_ID, Start_date, Price FROM EXCURSION_DATES WHERE EXCURSION_ID='" + excursionnID + "'";
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(query, conn);
try
{
conn.Open();
SqlDataReader rd = cmd.ExecuteReader();
int s=0;
while (rd.Read())
{
Dates dates = new Dates();
dates.ExcursionID = Convert.ToInt32(rd["Excursion_ID"]);
dates.StartDates = Convert.ToDateTime(rd["Start_date"]);
dates.Prices = Convert.ToDouble(rd["Price"]);
datesList.Add(dates);
}
}
catch (Exception EX)
{
}
return datesList;
}
}
<asp:GridView ID="gvDates" runat="server" Width="100%" AutoGenerateColumns="false"
OnRowCommand="grd_RowCommand" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btn" CausesValidation="false" CommandName="YourCommandName"
CommandArgument='<%#Eval("Excursion_ID") %>' runat="server" Text="Text" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void grd_RowCommand(object sender, GridViewCommandEventArgs e)
{
string number = (string)e.CommandArgument;
if (number==null) return;
switch (e.CommandName)
{
case "YourCommandName":
Load(number);
break;
// some others command
}
}
OR without rowcommand
<asp:GridView ID="gvDates" runat="server" Width="100%" AutoGenerateColumns="false" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btn" CausesValidation="false" OnClick="btnClick"
CommandArgument='<%#Eval("Excursion_ID") %>' runat="server" Text="Text" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void btnClick(object sender, EventArgs e)
{
Button btn=(Button)sender;
if(btn==null) return;
string number = (string)btn.CommandArgument;
if (number==null) return;
Load(number);
}
In your .aspx page, specify the id of the GridView button to the ExcursionID. You can use buttonfield or place a button in a template column for that.

iterate through ALL rows in a GridView

<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkSelected" runat="server" Checked="false"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
elow code works fine but there is a bug :
if Employee object has return 5 rows and i am trying to checked the check box based on the ids but instead its just matching only the last id - it suppose to checked all 5 rows..
List<Employee> result = new List<Employee>();
long Id = (long)Session["Id"];
result = Employee.GetEmployeeById(Id);
foreach (GridViewRow row in gv.Rows)
{
CheckBox chkBox = row.FindControl("chkSelected") as CheckBox;
if (c != null)
{
if (result.Count > 0)
{
foreach (Employee item in result)
{
Label Id = row.FindControl("lblId") as Label;
if (Id.Text == item.Id.ToString())
{
chkBox.Checked = true;
}
else
{
chkBox.Checked = false;
}
}
}
Look at your logic - you only have the one checkbox. You're unchecking and checking the same control in the employee loop. Does each grid row have a checkbox that should be selected based on the condition the id exists in the employee list?
foreach (GridViewRow row in gv.Rows)
{
Label Id = row.FindControl("lblId") as Label;
var result = Employee.GetEmployeeById(Id.Text);
if (result.Count > 0)
{
CheckBox chkBox = row.FindControl("chkSelected") as CheckBox;
if (chkBox != null)
{
chkBox.Checked = result.Any(x => x.Id.ToString() == Id.Text);
}
}
}

check/uncheckbox in gridview tracking

i have a below gridview control with a checkbox on it, so my question is when i hit on save button i able to find the checkbox which have been checked and till here no problem, but the problem started when the user tries to uncheck the checkedbox so how would i track the changes and save it into the db that has been checked. anyhelp?
List<Employee> result = new List<Employee>();
long Id = (long)Session["Id"];
result = Employee.GetEmployeeById(Id);
foreach (GridViewRow row in gv.Rows)
{
CheckBox chkBox = row.FindControl("chkSelected") as CheckBox;
if (c != null)
{
if (result.Count > 0)
{
foreach (Employee item in result)
{
Label Id = row.FindControl("lblId") as Label;
if (Id.Text == item.Id.ToString())
{
chkBox.Checked = true;
}
else
{
chkBox.Checked = false;
}
}
}
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkSelected" runat="server" Checked="false"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
<script language="javascript" type="text/javascript">
function SelectAll(cb)
{
var gvVar = document.getElementById("<%= gv.ClientID %>");
var cell;
if (gvVar.rows.length > 0)
{
for (i=1; i<gvVar.rows.length; i++)
{
cell = gvVar.rows[i].cells[0];
for (j=0; j<cell.childNodes.length; j++)
{
if (cell.childNodes[j].type =="checkbox")
{
cell.childNodes[j].checked = document.getElementById(cb).checked;
}
}
}
}
}
//--------------------------------------------------------------------------------------------.
function Select(cb)
{
var total = parseInt('<%= this.gv.Rows.Count %>');
var counter=0;
var cbSelectAll=document.getElementById(cb);
var gvVar = document.getElementById("<%= gv.ClientID %>");
var cell;
if (gvVar.rows.length > 0)
{
for (i=1; i<gvVar.rows.length; i++)
{
cell = gvVar.rows[i].cells[0];
for (j=0; j<cell.childNodes.length; j++)
{
if (cell.childNodes[j].type =="checkbox")
{
if(cell.childNodes[j].checked)
counter++;
else
counter--;
}
}
}
}
if(counter==total)
cbSelectAll.checked=true;
else if(counter<total)
cbSelectAll.checked=false;
}
</script>
//----------------------------------------------------------------------------------------
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow && (e.Row.RowState == DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox cbSelect = (CheckBox)e.Row.Cells[0].FindControl("cbSelect");
CheckBox cbSelectAll = (CheckBox)this.gv.HeaderRow.FindControl("cbSelectAll");
cbSelect.Attributes.Add("onclick", "javascript:Select('" + cbSelectAll.ClientID + "')");
cbSelectAll.Attributes.Add("onclick", "javascript:SelectAll('" + cbSelectAll.ClientID + "')");
}
}
Yes, store the original value in a hidden field. If always starting with false, you could use JavaScript to set the hidden value to true when the user clicked the checkbox. Using JQuery, you could do:
<asp:TemplateField HeaderText="Select" ItemStyle-CssClass="Checked">
<ItemTemplate>
<asp:CheckBox ID="chkSelected" runat="server" Checked="false"></asp:CheckBox>
<asp:HiddenField iD="dh" runat="server" />
</ItemTemplate>
</asp:TemplateField>
$("#<%= Grid.ClientID %>").find(".Checked > :checkbox").each(function() {
$(this).siblings("input[type='hidden']").attr("value", "True");
});
Something like that. On Server side, parse the value and if true, then you know it changed.
HTH.
It may not be the brightest idea, but you can query the database for the current state, and the compare with what you have got from the web page during a postback button click, or something like that. Or you can go with Brians answer.
It is possible to persist a list of objects into the Viewstate and access it in a consequent postback. The only thing is that the object you are trying to persist must be defined as serializable.
Update:
The ViewState approach
I feel this may be suitable for your need, and it requires a bit of linq. You'd need to create a class as follows:
[Serializable()]
public class OptionState
{
//the id of the item
int ID {get;set;}
//state of the checkbox
bool Checked {get;set;}
}
Note the Serializable attribute. This is required for the instance to persist to the viewstate.
Add the list of options to the viewstate:
var lstOptions = (from x in <your_option_store>
select new OptionState{ID = x.ID, Checked = x.Checked}).ToList();
ViewState.Add("options", lstOptions);
Here is a bit of code that should go into your button click:
foreach(GridViewRow row in gvOptions.Rows)
{
//not writing the bit of code
//which gets the ID and the
//state of checkbox of
//the gridview row being processed
OptionState currentState = GetOptionStateObjectFromRow(row);
List<OptionState> lstStates = (List<OptionState>) ViewState["options"];
OptionState originalState = lstStates.FirstOrDefault(x => x.ID == currentState.ID);
if(currentState.Checked != originalState.Checked)
{
//the appropriate db call needs to be done here.
}
}

Object and nested datalists

I am having trouble displaying my object in a datalist.
My object loks like this:
public class Course
{
private string courseName;
private DateTime[] courseDates;
public string CourseName
{
get { return courseName; }
set { courseName = value; }
}
public DateTime[] CourseDates
{
get { return courseDates; }
set {
foreach (DateTime dt in courseDates)
{
if (dt < DateTime.Now)
throw new Exception("The date of the course has to be after todays date.");
}
courseDates = value; }
}
public Course(string _courseName, DateTime[] _courseDates)
{
courseName = _courseName;
courseDates = _courseDates;
}
}
When I try to display it in a datalist the name of the course looks ok. But The dates are not shown.
So I was thinking I needed a nested datalist but then I don't know how to fill the second datalist with the dates in the object.
I've show two solutions:
<asp:DataList ID="DataList1" runat="server"
onitemdatabound="DataList1_ItemDataBound">
<ItemTemplate>
<td><%# DataBinder.Eval(Container.DataItem, "CourseName")%></td>
<td><%# RenderDates( DataBinder.Eval(Container.DataItem, "CourseDates"))%></td>
<td>
<asp:DataList ID="DateList" runat="server">
<ItemTemplate>
<td><%# Container.DataItem%></td>
</ItemTemplate>
</asp:DataList>
</td>
</ItemTemplate>
</asp:DataList>
and
public string RenderDates(object dates)
{
DateTime[] ds = dates as DateTime[];
StringBuilder sb = new StringBuilder();
if( ds != null && ds.Length > 0)
{
sb.Append(ds[0]);
for (int i = 1; i < ds.Length; i++)
{
sb.AppendFormat(" - {0}", ds[i]);
}
}
return sb.ToString();
}
protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
DataListItem item = e.Item;
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
var innerList= (DataList)item.FindControl("DateList");
innerList.DataSource = ((Course) item.DataItem).CourseDates;
innerList.DataBind();
}
}

Resources