I have a grid, which is filled with data after a button is pressed.
It has columns for every day of a certain month:
When the user presses the Edit button, I want the labels (showing text dayLabelText) to be replaced by controls for entering data of a particular value for that day of the month.
But when I press the Edit button, all the controls disappear:
When I press the Cancel button, nothing changes.
How should I modify the code shown below in order to fix this bug (when I press Edit, the dropdown lists should be shown, when I press Cancel - the text fields) ?
*.aspx file:
<%# Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="plan.aspx.cs" Inherits="plan"
EnableViewState="true" ViewStateMode="Enabled" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server" EnableViewState="true" ViewStateMode="Enabled">
[...]
<asp:GridView
ID="dailyPlanGrid"
runat="server"
OnRowCancelingEdit="dailyPlanGrid_RowCancelingEdit"
OnRowEditing="dailyPlanGrid_RowEditing"
AutoGenerateColumns="False" OnRowDataBound="dailyPlanGrid_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Edit" ShowHeader="False" HeaderStyle-HorizontalAlign="Left">
<EditItemTemplate>
<asp:LinkButton ID="lbkUpdate" runat="server" CausesValidation="True" CommandName="Update" Text="Update"></asp:LinkButton>
<asp:LinkButton ID="lnkCancel" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"></asp:LinkButton>
</EditItemTemplate>
<ItemTemplate>
<asp:LinkButton ID="lnkEdit" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="">
<EditItemTemplate>
<asp:Label ID="titleLabelEdit" runat="server" Text='<%# Bind("Title") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="titleLabelItem" runat="server" Text='<%# Bind("Title") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:Content>
.aspx.cs file:
public partial class plan : System.Web.UI.Page
{
[...]
private void UpdateGrid(int year, int month, string userName, bool updateTableCall = false)
{
[...]
DisplaySelectedPlan(year, month, userName, updateTableCall);
}
private void DisplaySelectedPlan(int year, int month, string userName, bool updateTableCall = false)
{
DataTable data = new DataTable();
DataColumn titleColumn = new DataColumn();
titleColumn.ColumnName = "Title";
titleColumn.Caption = "";
data.Columns.Add(titleColumn);
INumberOfDaysInMonthCalculator numberOfDaysInMonthCalculator = new NumberOfDaysInMonthCalculator();
int daysInMonth = numberOfDaysInMonthCalculator.GetNumberOfDays(year, month);
if (updateTableCall)
{
AddDayColumns(daysInMonth);
}
var row = data.NewRow();
row["Title"] = "Вид";
data.Rows.Add(row);
Database.Instance.Open();
IDailyWorkingTimesReader dailyWorkingTimesReader = new DailyWorkingTimesReader(Database.Instance.SqlCommandFactory);
dailyWorkingTimesReader.ReadData(year, month, userName);
IDictionary<int, DateTime> startTimesByDay = dailyWorkingTimesReader.GetStartTimes();
IDictionary<int, DateTime> endTimesByDay = dailyWorkingTimesReader.GetEndTimes();
AddStartRow(data, daysInMonth, startTimesByDay);
AddEndRow(data, daysInMonth, endTimesByDay);
var holidayRow = data.NewRow();
holidayRow["Title"] = "Госудаственный праздник";
data.Rows.Add(holidayRow);
var preHolidayRow = data.NewRow();
preHolidayRow["Title"] = "Предпраздничный день";
data.Rows.Add(preHolidayRow);
dailyPlanGrid.ShowHeaderWhenEmpty = true;
dailyPlanGrid.DataSource = data;
dailyPlanGrid.DataBind();
}
private void AddDayColumns(int daysInMonth)
{
for (int i = 1; i <= daysInMonth; i++)
{
TemplateField dayColumn = new TemplateField();
dayColumn.HeaderText = "" + i;
dayColumn.EditItemTemplate = new DayEditItemTemplate(i);
dayColumn.ItemTemplate = new DayItemTemplate(i);
dailyPlanGrid.Columns.Add(dayColumn);
}
}
private static void AddEndRow(DataTable data, int daysInMonth, IDictionary<int, DateTime> endTimesByDay)
{
var endRow = data.NewRow();
endRow["Title"] = "Конец";
FillTimeColumns(daysInMonth, endRow, endTimesByDay);
data.Rows.Add(endRow);
}
private static void AddStartRow(DataTable data, int daysInMonth, IDictionary<int, DateTime> startTimesByDay)
{
var startRow = data.NewRow();
startRow["Title"] = "Начало";
FillTimeColumns(daysInMonth, startRow, startTimesByDay);
data.Rows.Add(startRow);
}
private static void FillTimeColumns(int daysInMonth, DataRow row, IDictionary<int, DateTime> timesByDay)
{
for (int i = 1; i <= daysInMonth; i++)
{
if (timesByDay.ContainsKey(i))
{
row["Day" + i] = timesByDay[i];
}
}
}
private void CreatePlanForSelectedEmployeeAndMonth(int year, int month, string userName)
{
IDailyPlanCreator dailyPlanCreator = new DailyPlanCreator(Database.Instance.SqlCommandFactory,
new NumberOfDaysInMonthCalculator());
Database.Instance.Open();
dailyPlanCreator.CreateDailyPlan(year, month, userName);
}
protected void updateTableButton_Click(object sender, EventArgs e)
{
// Here the grid is initialized (after the user presses some button)
DataTable dataTable = monthList.DataSource as DataTable;
DataRow row = dataTable.Rows[monthList.SelectedIndex] as DataRow;
IUserNameExtractor userNameExtractor = new UserNameExtractor();
UpdateGrid((int)row["year"], (int)row["month"], userNameExtractor.ExtractUserNameWithoutDomain(Request.LogonUserIdentity.Name), true);
}
protected void dailyPlanGrid_RowEditing(object sender, GridViewEditEventArgs e)
{
dailyPlanGrid.EditIndex = e.NewEditIndex;
DataTable dataTable = monthList.DataSource as DataTable;
DataRow row = dataTable.Rows[monthList.SelectedIndex] as DataRow;
IUserNameExtractor userNameExtractor = new UserNameExtractor();
UpdateGrid((int)row["year"], (int)row["month"], userNameExtractor.ExtractUserNameWithoutDomain(Request.LogonUserIdentity.Name));
}
protected void dailyPlanGrid_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
dailyPlanGrid.EditIndex = -1;
DataTable dataTable = monthList.DataSource as DataTable;
DataRow row = dataTable.Rows[monthList.SelectedIndex] as DataRow;
IUserNameExtractor userNameExtractor = new UserNameExtractor();
UpdateGrid((int)row["year"], (int)row["month"], userNameExtractor.ExtractUserNameWithoutDomain(Request.LogonUserIdentity.Name));
}
protected void dailyPlanGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if ((e.Row.RowType == DataControlRowType.DataRow) && (dailyPlanGrid.EditIndex > -1))
{
DataTable dataTable = monthList.DataSource as DataTable;
DataRow row = dataTable.Rows[monthList.SelectedIndex] as DataRow;
int year = (int)row["year"];
int month = (int)row["month"];
INumberOfDaysInMonthCalculator numberOfDaysInMonthCalculator = new NumberOfDaysInMonthCalculator();
int daysInMonth = numberOfDaysInMonthCalculator.GetNumberOfDays(year, month);
if (e.Row.RowIndex == 0)
{
// Type
for (int i=1; i <= daysInMonth; i++)
{
DropDownList dropDownList = (DropDownList) e.Row.FindControl("dayDropDownList" + i);
if (dropDownList != null)
{
dropDownList.Items.Clear();
dropDownList.Items.Add("item1");
dropDownList.Items.Add("item2");
}
}
}
else if (e.Row.RowIndex == 1)
{
// Start time of the business day
}
else if (e.Row.RowIndex == 2)
{
// End time of the business day
}
else if (e.Row.RowIndex == 3)
{
// Holiday
}
else if (e.Row.RowIndex == 4)
{
// Pre-holiday
}
}
}
}
Note that the columns for all days are added programmatically. It must be done in this way because
the customer wants the days to be in displayed in columns (one column per day, not one row per day) and
the number of days in a particular month is different.
Therefore, in I add columns with 2 types of templates - one for displaying and one for editing day-related data.
private void AddDayColumns(int daysInMonth)
{
for (int i = 1; i <= daysInMonth; i++)
{
TemplateField dayColumn = new TemplateField();
dayColumn.HeaderText = "" + i;
dayColumn.EditItemTemplate = new DayEditItemTemplate(i);
dayColumn.ItemTemplate = new DayItemTemplate(i);
dailyPlanGrid.Columns.Add(dayColumn);
}
}
DayEditItemTemplate.cs:
public class DayEditItemTemplate : ITemplate
{
private readonly int day;
public DayEditItemTemplate(int aDay)
{
day = aDay;
}
public void InstantiateIn(Control container)
{
DropDownList dropDownList = new DropDownList();
dropDownList.ID = "dayDropDownList"+day;
dropDownList.Items.Add("item1");
dropDownList.Items.Add("item2");
dropDownList.Items.Add("item3");
container.Controls.Add(dropDownList);
}
}
DayItemTemplate.cs:
public class DayItemTemplate : ITemplate
{
private readonly int day;
public DayItemTemplate(int aDay)
{
day = aDay;
}
public void InstantiateIn(Control container)
{
Label dayLabel = new Label();
dayLabel.ID = "dayLabelText"+day;
dayLabel.Text = "dayLabelText";
container.Controls.Add(dayLabel);
}
}
Update 1: The error has something to do with the fact that I add the day-oriented controls programmatically.
Justification: When I a column in the **.aspx* file, the problem does not occur (with that particular column).
<asp:TemplateField HeaderText="DayX">
<EditItemTemplate>
<asp:DropDownList ID="dayXdropDownList" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="dayXLabel" Text="dayXLabel" runat="server" />
</ItemTemplate>
</asp:TemplateField>
You need to add EditItemTemplate for each column and bind it as following,
<EditItemTemplate>
<asp:Label ID="titleLabelEdit" runat="server" Text='<%# Bind("Title") %>' />
</EditItemTemplate>
Related
protected void Gridproducts_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink hp = new HyperLink();
hp = (HyperLink)e.Row.FindControl("linkSelectprd");
var Pid = DataBinder.Eval(e.Row.DataItem, "product_id").ToString();
var Catid = Request.QueryString["Cid"].ToString();
hp.NavigateUrl = "Sales.aspx?Cid="+Catid+"&"+"Pid="+Pid;
if (!IsPostBack && Request.QueryString["Pid"] != null)
{
this is the variable in which the value of quantity increments
int i=0;
lbltotalquantity.Text = i.ToString() + 1;
}
}
}
}
I use LinkButtons inside a Grid template. I want to be able to raise events when clicking the LinkButtons the value of lable is incremented on + link and decrementd on - link button as lable contains the quantity of Products added to invoice. How can I accomplish this?
I believe this is what you want....
You don't do the increment in RowDataBound because RowDataBound trigger when you are binding the GridView
.aspx
<asp:ScriptManager ID="sm" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="up" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="gv" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Product">
<ItemTemplate>
<asp:Label ID="lblProduct" runat="server" Text='<%# Eval("Product") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Quantity">
<ItemTemplate>
<asp:Label ID="lblQuantity" runat="server" Text="0"></asp:Label>
<asp:LinkButton ID="lbtnPlus" runat="server" Text="+" OnClick="lbtnPlus_Click"></asp:LinkButton>
<asp:LinkButton ID="lbtnMinus" runat="server" Text="-" OnClick="lbtnMinus_Click"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="gv" />
</Triggers>
</asp:UpdatePanel>
.cs
protected void Page_Load(object sender, EventArgs e)
{
// Check
if (!IsPostBack)
{
// Variable
string[] product = { "Dell", "Asus", "Acer", "Toshiba", "Fujishu", "VAIO" };
DataTable dt = new DataTable();
dt.Columns.Add("Product");
for (int i = 0; i < product.Length; i++)
dt.Rows.Add(product[i]);
gv.DataSource = dt;
gv.DataBind();
// Dispose
dt.Dispose();
}
}
private void DoTheMath(GridViewRow row, bool isAdd)
{
// Variable
bool isNumber = false;
int currentValue = 0;
// Find Control
Label lblQuantity = row.FindControl("lblQuantity") as Label;
// Check
if (lblQuantity != null)
{
// Check
if (lblQuantity.Text.Trim() != string.Empty)
{
isNumber = int.TryParse(lblQuantity.Text.Trim(), out currentValue);
// Check
if (isNumber)
{
// Is Add
if (isAdd)
currentValue++;
else
{
// Check cannot be less than 0
if (currentValue > 0)
currentValue--;
}
}
// Set to TextBox
lblQuantity.Text = currentValue.ToString();
}
}
}
protected void lbtnPlus_Click(object sender, EventArgs e)
{
// Get
LinkButton lbtn = sender as LinkButton;
GridViewRow row = lbtn.NamingContainer as GridViewRow;
DoTheMath(row, true);
}
protected void lbtnMinus_Click(object sender, EventArgs e)
{
// Get
LinkButton lbtn = sender as LinkButton;
GridViewRow row = lbtn.NamingContainer as GridViewRow;
DoTheMath(row, false);
}
This is my code behind code. I want to populate the DropDownList once the user clicked edit but the DropDownList I'm getting is null. Why?
protected void SupportSchedule_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EditRow")
{
int rowIndex = ((GridViewRow)((ImageButton) e.CommandSource).NamingContainer).RowIndex;
GridViewRow row = (GridViewRow)(((ImageButton) e.CommandSource).NamingContainer);
SupportScheduleTable.EditIndex = rowIndex;
shift.Enabled = true;
resourcedate.Enabled = true;
ListItemCollection c = db.fillList();
DropDownList ddl1 = row.FindControl("ddlshiftmanager") as DropDownList;
DropDownList ddl2 = row.FindControl("ddldispatcherone") as DropDownList;
DropDownList ddl3 = row.FindControl("ddldispatchertwo") as DropDownList;
if (c != null && ddl1 != null)
{
ddl1.DataSource = c;
ddl2.DataSource = c;
ddl3.DataSource = c;
ddl1.DataBind();
ddl2.DataBind();
ddl3.DataBind();
}
getSupportSchedule();
}
else if (e.CommandName == "CancelUpdate")
{
//some codes here
} else if (e.CommandName == "UpdateRow")
{
//some codes here
}
}
//asp code
<asp:GridView ID="SupportScheduleTable" AutoGenerateColumns="False" Width="100%" runat="server" OnRowCommand="SupportSchedule_RowCommand">
<Columns>
<asp:TemplateField HeaderText="Shift Manager">
<EditItemTemplate>
<asp:DropDownList ID="ddlshiftmanager" runat="server" Width="99%"></asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("shift_manager") %>'></asp:Label>
</ItemTemplate>
<HeaderStyle Width="32%" />
</asp:TemplateField>
<asp:TemplateField ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:ImageButton ID="lbEdit" CssClass="btn" ImageUrl="~/Files/edit.png" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="EditRow" runat="server"></asp:ImageButton>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="lbUpdate" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="UpdateRow" runat="server">Update</asp:LinkButton>
<asp:LinkButton ID="lbCancel" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="CancelUpdate" runat="server" CausesValidation="false">Cancel</asp:LinkButton>
</EditItemTemplate>
<HeaderStyle Width="2%" />
</asp:TemplateField>
//two dropdownlists before image button
</Columns>
</GridView>
I just added the ImageButton here in the recent update but this is my original code that doesn't work.
I used a SqlDataSource instead of adding the list items from the back
and this is what I used to get the selected value of the DropDownList.
else if (e.CommandName == "UpdateRow")
{
int rowIndex = ((GridViewRow)((LinkButton)e.CommandSource).NamingContainer).RowIndex;
DropDownList ddlshift = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddlshiftmanager");
DropDownList ddlone = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddldispatcherone");
DropDownList ddltwo = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddldispatchertwo");
string manager = ddlshift.SelectedValue;
string one = ddlone.SelectedValue;
string two = ddltwo.SelectedValue;
int supportID = Convert.ToInt32(e.CommandArgument);
String sh = shift.Text;
String date = resourcedate.Text;
db.updateSS(supportID, sh, manager, one, two,date);
SupportScheduleTable.EditIndex = -1;
shift.Enabled = false;
resourcedate.Enabled = false;
getSupportSchedule();
}
Your answer is a correct way to handle the issue you are seeing. But, in case you didn't figure out the actual cause...
The ImageButton you click is in your ItemTemplate. The DropDownList you want to bind is in your EditItemTemplate. lbEdit exists when you are not in edit mode but ddlshiftmanager only exists when you are.
So, the fix is to put the GridView in edit mode. Notice that this is something you actually already started to do. You need to set the EditIndex, re-bind the GridView, then get the row again. You'll then have the row in edit mode. This row should now contain ddlshiftmanager.
protected void SupportSchedule_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EditRow")
{
int rowIndex = ((GridViewRow)((ImageButton) e.CommandSource).NamingContainer).RowIndex;
// Set the index to edit
SupportScheduleTable.EditIndex = rowIndex;
// Re-bind the GridView to put it in edit mode
SupportScheduleTable.DataSource = /* your data source */
SupportScheduleTable.DataBind();
// Get the row at the index. The row will be the
// row reflected in edit mode.
GridViewRow editRow = SupportScheduleTable.Rows[rowIndex];
// Find your DropDownLists in this edit row
DropDownList ddl1 = editRow.FindControl("ddlshiftmanager") as DropDownList;
DropDownList ddl2 = editRow.FindControl("ddldispatcherone") as DropDownList;
DropDownList ddl3 = editRow.FindControl("ddldispatchertwo") as DropDownList;
shift.Enabled = true;
resourcedate.Enabled = true;
ListItemCollection c = db.fillList();
if (c != null && ddl1 != null)
{
ddl1.DataSource = c;
ddl2.DataSource = c;
ddl3.DataSource = c;
ddl1.DataBind();
ddl2.DataBind();
ddl3.DataBind();
}
getSupportSchedule();
}
// Everything else...
}
I have created user control named CRE.ascx,this control has 3 dropdownlist.
First dropdownlist bind data on pageload.Second and third based on SelectedIndexChanged.
<table cellspacing="0" cellspading="0" style="width:550px;height:30px;">
<tr>
<td style="width:30%;">
<asp:DropDownList ID="ddlCRE" runat="server" Height="20px" Width="145px" OnSelectedIndexChanged="ddlCRE_SelectedIndexChanged" AutoPostBack="true">
</asp:DropDownList>
</td>
<td style="width:30%;">
<asp:DropDownList ID="ddlDataPoints" runat="server" Height="20px" Width="145px" OnSelectedIndexChanged="ddlDataPoints_SelectedIndexChanged" AutoPostBack="true">
</asp:DropDownList>
</td>
<td style="width:30%;">
<asp:DropDownList ID="ddlErrorCode" runat="server" Height="20px" Width="145px" OnSelectedIndexChanged="ddlErrorCode_SelectedIndexChanged" AutoPostBack="true">
</asp:DropDownList>
</td>
<td style="width:10%;">
<asp:TextBox ID="tbxErrorScore" runat="server" style="height:17px;border:0px;font-family:'Segoe UI';font-size:13px;font-weight:500;color:white;background-color:#333333;
width:65px;" ReadOnly="true"> </asp:TextBox>
</td>
</tr>
</table>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Get Ticket Type Values
dbtickettype = helpdsktcktusrHandler.GetTicketType("DPT0001");
ddlCRE.DataSource = dbtickettype;
ddlCRE.DataValueField = "Type_ID";
ddlCRE.DataTextField = "Type_Name";
ddlCRE.DataBind();
ddlCRE.Items.Insert(0, new ListItem("Select Type", "SLCT0000"));
}
else
{
}
}
protected void ddlCRE_SelectedIndexChanged(object sender, EventArgs e)
{
string selectedTypeID = ddlCRE.SelectedValue.ToString();
try
{
if (selectedTypeID == "SLCT0000")
{
ddlDataPoints.Items.Clear();
ddlErrorCode.Items.Clear();
tbxErrorScore.Text = string.Empty;
}
else
{
//Get Category Details
dbticketCategory = helpdsktcktusrHandler.GetTicketCategoryDetails(selectedTypeID);
//Binding Ticket Type values to Listbox
ddlDataPoints.DataSource = dbticketCategory;
ddlDataPoints.DataValueField = "Category_ID";
ddlDataPoints.DataTextField = "Category_Name";
ddlDataPoints.DataBind();
ddlDataPoints.Items.Insert(0, new ListItem("Select Category", "SLCT0000"));
//Clear Items
ddlErrorCode.Items.Clear();
tbxErrorScore.Text = string.Empty;
}
}
catch (Exception ex)
{
}
}
protected void ddlDataPoints_SelectedIndexChanged(object sender, EventArgs e)
{
string selectedCatID = ddlDataPoints.SelectedValue.ToString();
try
{
if (selectedCatID == "SLCT0000")
{
ddlErrorCode.Items.Clear();
tbxErrorScore.Text = string.Empty;
}
else
{
//Get Category Details
dbticketSubCategory = helpdsktcktusrHandler.GetTicketSubCategoryDetails(selectedCatID);
//Binding Ticket Type values to Listbox
ddlErrorCode.DataSource = dbticketSubCategory;
ddlErrorCode.DataValueField = "Sub_Category_ID";
ddlErrorCode.DataTextField = "Sub_Category_Name";
ddlErrorCode.DataBind();
ddlErrorCode.Items.Insert(0, new ListItem("Select Subcategory", "SLCT0000"));
//Clear Items
tbxErrorScore.Text = string.Empty;
}
}
catch (Exception ex)
{
}
}
protected void ddlErrorCode_SelectedIndexChanged(object sender, EventArgs e)
{
string selectedSubcatID = ddlErrorCode.SelectedValue.ToString();
try
{
if (selectedSubcatID == "SLCT0000")
{
tbxErrorScore.Text = string.Empty;
}
else
{
//Get Category Details
dbticketIssues = helpdsktcktusrHandler.GetTicketIssueDetails(selectedSubcatID);
////Binding Ticket Type values to Listbox
//ddlstIssue.DataSource = dbticketIssues;
//ddlstIssue.DataValueField = "IssueID";
//ddlstIssue.DataTextField = "Issue_Name";
//ddlstIssue.DataBind();
tbxErrorScore.Text = dbticketIssues.Rows[0][1].ToString();
}
}
catch (Exception ex)
{
}
}
then register directive and an instance of the user control added to the page.
In this main page, i have added one Gridview, user control UC1 and two buttons
included in the ItemTemplate.
<%# Register src="~/CRE.ascx" TagName="InsertNewCRE" TagPrefix="uc1" %>
<asp:UpdatePanel ID="MainUpdatePanel" runat="server">
<ContentTemplate>
<div id="dvsubCRE" class="dvsubCRE" runat="server">
<!-----[[[ GRIDVIEW ADDING CRE ]]]----->
<div id="dvAddingErrorInfo" class="dvAddingErrorInfo">
<!-- LOAD CRE DROPDOWN INFO GRID -->
<asp:GridView ID="gvCREInfo" runat="server" CssClass="gvErrorInfo" AlternatingRowStyle-CssClass="" ShowFooter="false" ShowHeader="false"
EnableViewState="True" GridLines="None" EmptyDataText="No records found" AutoGenerateColumns="true" CaptionAlign="Left" CellPadding="0"
ShowHeaderWhenEmpty="True" OnRowCreated="gvCREInfo_RowCreated" OnRowCommand="gvCREInfo_RowCommand" >
<Columns>
<asp:BoundField DataField="RowNumber" />
<asp:TemplateField ItemStyle-Width="25%" ItemStyle-Height="20px">
<ItemTemplate>
<uc1:InsertNewCRE id="UC1InserCRE" runat="server" EnableViewState="true" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ItemStyle-Width="5%">
<ItemTemplate>
<asp:ImageButton ID="imgbtnAddCRE" runat="server" Width="20px" Height="20px" value="" ImageUrl="~/Images/Tracker/add.png"
CommandName="ButtonAddCRERow" CommandArgument="<%# ((GridViewRow) Container).RowIndex %>" />
<asp:ImageButton ID="imgbtnReoveCRE" runat="server" Width="20px" Height="20px" value="" Visible="false" ImageUrl="~/Images/Tracker/delete.png" CommandName="ButtonRemoveCRERow" CommandArgument="<%# ((GridViewRow) Container).RowIndex %>" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<!-- LOAD CRE DROPDOWN INFO GRID CLOSE -->
</div>
<!-----[[[ GRIDVIEW ADDING CRE CLOSE ]]]----->
</div>
</ContentTemplate>
</asp:UpdatePanel>
When main page loads, user control UC1 loaded in the gridview and pull out the data from CRE.ascx page.I have bind dummy data on page load to the gridview.Add new row along with user control mentioned in the RowCommand.
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
DataTable dt = new DataTable();
DataRow dr = null;
dt.Columns.Add(new DataColumn("RowNumber", typeof(string)));
dr = dt.NewRow();
dr["RowNumber"] = 1;
dt.Rows.Add(dr);
ViewState["CurrentTable"] = dt;
gvCREInfo.DataSource = dt;
gvCREInfo.DataBind();
}
else
{
}
}
catch (Exception ex)
{
}
}
protected void gvCREInfo_RowCommand(object sender, GridViewCommandEventArgs e)
{
#region ADD NEW CRE ROW
if (e.CommandName == "ButtonAddCRERow")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = gvCREInfo.Rows[index];
int count = gvCREInfo.Rows.Count;
DataRow drCurrentRow = null;
UserControl UC1 = (UserControl)(row.Cells[0].FindControl("UC1InserCRE"));
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
for (int i = 0; i <= (count - 1); i++)
{
drCurrentRow = dtCurrentTable.NewRow();
dtCurrentTable.Rows.Add(drCurrentRow);
}
gvCREInfo.DataSource = dtCurrentTable;
gvCREInfo.DataBind();
}
#endregion
}
When i run this code working fine and i changed the first dropdownlist
it will pull data and bind to the second, like wise third one also.But when i click the add button selected data lost in the first row and second row control added not with data.How to retain existing selected data and load user control along with data it should not loss data event post back.Please help me and sort out this.
![enter image description here][1]
http://i.stack.imgur.com/wdYZv.jpg
Problem and Description:
I have a GridView with programmatically added DropDownLists on RowDataBound to every cell.
The DropDownLists all have Data Sources.
When I press a 'Save' button, it is meant to read all the selecteditems in the DropDownLists and save them to a database.
However, when I click on the button, it causes postback and deletes all of the controls in the GridView and therefore, none of them can be found in my button_click event.
After asking questions before and trying different techniques to try store the dropdownlists in Cache/Session state etc, I simply can't seem to be able to keep the dropdownlists or the data when I click the button.
Therefore, I am now trying to add an UpdatePanel and use AJAX to try stop the refresh of the GridView.
My attempt was as such:
<asp:GridView ID="gv_Rota" runat="server" AutoGenerateColumns="false" OnRowDataBound="gv_Rota_RowDataBound">
<HeaderStyle BackColor="#6a3d98" ForeColor="White" Height="20" />
<RowStyle HorizontalAlign="Center" Height="20px" Width="100px" />
<AlternatingRowStyle Height="20px" />
</asp:GridView>
</div>
<asp:Label ID="lbl_NameOfRota" runat="server" Text="New rota name:"></asp:Label>
<input runat="server" id="txt_RotaName" />
<asp:UpdatePanel runat="server" ID="RotaUpdatePanel">
<ContentTemplate>
<asp:Button ID="btn_AddRota" runat="server" Text="Add" OnClick="btn_AddRota_Click" CssClass="ButtonAdminPage" />
</ContentTemplate>
</asp:UpdatePanel>
As you can see, I placed the UpdatePanel around my button only, however, it still seemed to refresh the GridView and delete all the controls.
Questions:
Firstly, why did my attempt not work?
Secondly, how can I get around this problem using AJAX and Update Panels, or is there another method to get me what I need? (Baring in mind, if something else is suggested, I've probably already tried it).
EDIT 2:
Supplied Code:
This is when I bind the DropDownLists:
protected void gv_Rota_RowDataBound(object sender, GridViewRowEventArgs e)
{
for (int i = 1; i <= ColumnCount; i++)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int day = e.Row.RowIndex;
day += 1;
ddlShift = new DropDownList();
ddlShift.ID = "ddlShift" + "WK" + i.ToString() + "DAY" + day.ToString();
ddlShift.DataSource = DCListOfShifts;
ddlShift.DataValueField = "SHIFT_ID";
ddlShift.DataTextField = "SHIFT_NAME";
ddlShift.Attributes.Add("Place", i.ToString());
ddlShift.DataBind();
ddlShift.Items.Insert(0, new ListItem("Shift..."));
ddlShift.CssClass = "ddl_rotamanager";
e.Row.Cells[i].Controls.Add(ddlShift);
}
}
}
This is when I create the GridView dependant on the amount of columns passed:
private void BindGrid(int Amount)
{
gv_Rota.DataSource = null;
gv_Rota.Columns.Clear();
BoundField bfield = new BoundField();
bfield.HeaderText = "Days";
bfield.DataField = "Days";
gv_Rota.Columns.Add(bfield);
for (int i = 0; i < Amount; i++)
{
int week = i + 1;
string sWeek = "Week " + week.ToString();
TemplateField tfield = new TemplateField();
tfield.HeaderText = sWeek;
gv_Rota.Columns.Add(tfield);
}
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Days", typeof(string)));
dt.Rows.Add("M");
dt.Rows.Add("T");
dt.Rows.Add("W");
dt.Rows.Add("T");
dt.Rows.Add("F");
dt.Rows.Add("S");
dt.Rows.Add("S");
gv_Rota.DataSource = dt;
gv_Rota.DataBind();
}
This is where I get the selected amount of columns and call the method to create the GridView, I also store the amount in Cache:
protected void ddl_RotaAmountOfWeeks_SelectedIndexChanged(object sender, EventArgs e)
{
if (IsPostBack)
{
int Amount;
int.TryParse(ddl_RotaAmountOfWeeks.SelectedItem.ToString(), out Amount);
ColumnCount = Amount;
Cache.Add("columnCount", ColumnCount, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 60, 0), CacheItemPriority.Default, null);
BindGrid(Amount);
}
}
Button code:
protected void btn_AddRota_Click(object sender, EventArgs e)
{
//My first attempt at trying to save the GridView, realising I Cache'd the GridView before selecting items.
//gv_Rota = (GridView)Cache["cacheGridView"];
//Set of the size of the array to the amount of rows * colums
//this will be the maximum amount of events added
int arraysize = gv_Rota.Rows.Count * (int)Cache["columnCount"];
//the current array item being added
int arrayitem = 0;
//Finally an array of ROTA_EVENTS to pass to WCF
wsPersonnel.DC_WFM_ROTA_EVENTS[] arrayofRotaEvents = new wsPersonnel.DC_WFM_ROTA_EVENTS[arraysize];
foreach (GridViewRow row in gv_Rota.Rows)
{
for (int i = 1; i <= (int)Cache["columnCount"]; i++)
{
int day = row.RowIndex;
day += 1;
DropDownList DDL1 = (DropDownList)gv_Rota.Rows[row.RowIndex].Cells[i].FindControl("ddlShiftWK" + i.ToString() + "DAY" + day.ToString());
wsPersonnel.DC_WFM_ROTA_EVENTS dcEvent = new wsPersonnel.DC_WFM_ROTA_EVENTS
{
SHIFT_ID = DDL1.SelectedItem.Value,
WEEK = i,
WEEKSpecified = true,
DAY = day,
DAYSpecified = true,
};
arrayofRotaEvents[arrayitem++] = dcEvent;
}
}
wsP.AddRota(new wsPersonnel.DC_WFM_ROTA
{
ROTA_NAME = txt_RotaName.Value,
PERIOD_TYPE = 1,
PERIOD_TYPESpecified = true,
PERIOD_AMOUNT = ColumnCount,
PERIOD_AMOUNTSpecified = true,
ROTA_EVENTS = arrayofRotaEvents
});
}
Example of what the GridView looks like:
If you want to stop postback on button click inside the update panel then you can try this
<asp:UpdatePanel runat="server" ID="RotaUpdatePanel" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button ID="btn_AddRota" runat="server" Text="Add" OnClick="btn_AddRota_Click" CssClass="ButtonAdminPage" ClientIDMode="AutoID"/>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btn_AddRota" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
I have two GridViews in which I populate Data on PageStart from database. When I refresh the page (on Post Back), I could not see the datatable content. so I thought of Databinding the GridView again on every pageload. In order to bind the Data I need to store the Data somewhere temporarily. Which one is the Best method to store data temporarily?
In my First Grid there are about 10 rows and in the Second GridView I have about 200 rows. and I'm not using Paging
Here's a fully working sample using ViewState but you can change it for other caching methods.
Default.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView runat="server" ID="gvProd" AutoGenerateColumns="false" OnRowDataBound="gvProd_RowDataBound" OnRowCommand="gvProd_RowCommand">
<Columns>
<asp:TemplateField HeaderText="Product">
<ItemTemplate>
<asp:Literal runat="server" ID="litNm"></asp:Literal>
<asp:DropDownList runat="server" ID="ddlQty"></asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Add To Cart">
<ItemTemplate>
<asp:LinkButton runat="server" ID="lbnAdd" Text="Add To Cart" CommandName="AddToCart"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<hr />
<asp:GridView runat="server" ID="gvCart" AutoGenerateColumns="false" OnRowDataBound="gvCart_RowDataBound" OnRowCommand="gvCart_RowCommand">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Literal runat="server" ID="litNm"></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox runat="server" ID="txtQty"></asp:TextBox>
<asp:Button runat="server" ID="btnUpdate" Text="Update Qty" CommandName="UpdateCart" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class Default : System.Web.UI.Page
{
[Serializable]
public class Product
{
public int PID { get; set; }
public string Name { get; set; }
public Product(int i) { this.PID = i; this.Name = "product " + i.ToString(); }
}
[Serializable]
public class CartItem
{
public Product Prod { get; set; }
public int Qty { get; set; }
public CartItem(Product p, int q) { this.Prod = p; this.Qty = q; }
}
public List<CartItem> myCart = new List<CartItem>();
public List<CartItem> MyCart
{
get
{
if (ViewState["cart"] == null)
{
ViewState["cart"] = new List<CartItem>();
}
return ViewState["cart"] as List<CartItem>;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
BindProdGrid();
}
protected void BindProdGrid()
{
gvProd.DataSource = GetProducts();
gvProd.DataBind();
}
protected List<Product> GetProducts()
{
var ret = new List<Product>();
ret.Add(new Product(1));
ret.Add(new Product(2));
return ret;
}
protected void gvProd_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "AddToCart")
{
var row = (e.CommandSource as LinkButton).NamingContainer as GridViewRow;
var ddl = row.FindControl("ddlQty") as DropDownList;
var qty = Convert.ToInt32(ddl.SelectedValue);
var pid = Convert.ToInt32(e.CommandArgument);
AddToCart(pid, qty, increase: true);
BindCartGrid(this.MyCart);
}
}
protected void AddToCart(int pid, int qty, bool increase = false)
{
var cartItem = this.MyCart.Find(o => o.Prod.PID == pid);
if (cartItem == null)
this.MyCart.Add(new CartItem(new Product(pid), qty));
else
if (increase)
cartItem.Qty += qty;
else
cartItem.Qty = qty;
}
protected void gvProd_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var item = e.Row.DataItem as Product;
var litNm = e.Row.FindControl("litNm") as Literal;
litNm.Text = item.Name;
var ddlQty = e.Row.FindControl("ddlQty") as DropDownList;
ddlQty.Items.Add(new ListItem("1", "1"));
ddlQty.Items.Add(new ListItem("10", "10"));
var lbnAdd = e.Row.FindControl("lbnAdd") as LinkButton;
lbnAdd.CommandArgument = item.PID.ToString();
}
}
protected void BindCartGrid(List<CartItem> items)
{
gvCart.DataSource = items;
gvCart.DataBind();
}
protected void gvCart_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var item = e.Row.DataItem as CartItem;
var litNm = e.Row.FindControl("litNm") as Literal;
litNm.Text = item.Prod.Name + " (pid:" + item.Prod.PID.ToString() + ")";
var txtQty = e.Row.FindControl("txtQty") as TextBox;
txtQty.Text = item.Qty.ToString();
txtQty.Attributes["data-pid"] = item.Prod.PID.ToString();
}
}
protected void gvCart_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "UpdateCart")
{
var row = (e.CommandSource as Button).NamingContainer as GridViewRow;
var txtQty = row.FindControl("txtQty") as TextBox;
var qty = Convert.ToInt32(txtQty.Text);
var pid = Convert.ToInt32(txtQty.Attributes["data-pid"]);
AddToCart(pid, qty, increase: false);
BindCartGrid(this.MyCart);
}
}
}
}
Usage of Cache object vs Session again will depend upon whether you want the data to be stored temporarily per session or for all the sessions you want to store the same data.
Session can be used if you want the same data to be maintained only for a particular session of your application.
Cache can be used for all the user sessions across your application.
The best place to store the data will be sessions. Viewstate will bring all the data on client side which is an undesirable network/bandwidth overhead.
your PageStart should look like this:
public void PageStart()
{
if(Session["dt"] == null || !(Session["dt"] is datatable)){
datatable dt;
///your dt populating code
Session["dt"] = dt;
}
yourGridView.datasource = (datatable)Session["dt"];
yourGridView.databind();
}
To address data persistence between postbacks you have several options. I am really against ViewState except in very specific cases where you have a very little amount of data (that's where Microsoft fail in WebForms - its default behaviour is DemoWare).
I would suggest keeping your data in a Cache object and upon postback, read it from that object. But it really depends on your specific use case. There are different techniques.
This is all what you need to do.
Place you method or function which fills the gridview with data like this.
private void FillGrid()
{
DataTable dt = new DataTable();
dt = //Fill you datatable
Gridview1.DataSource = dt;
Gridview1.DataBind();
}
This is what you gotta do on pageload event.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
this.FillGrid();
}
}