How to temporarily store DataTable after Binding - c#

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();
}
}

Related

How do i get id of colunm in gridview c# asp.net and open another page using that id?

How do i get id of column in grid view c# asp.net using a button and the open another web-part that will collect information fromsl server using that id from grid-view?
I have done this for my grid view:
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnView" runat="server" Text="View" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And for the information from sqlserver that is being filled in gridview the code is:
protected void GridView_Load(object sender, EventArgs e)
{
using (DBEntitiesModelConn DbContext = new DBEntitiesModelConn())
{
try
{
GridView.AutoGenerateColumns = true;
var ApplicationData = from i in DbContext.DBEntity
select new
{
CompanyName = i.Name.ToString(),
ApplicationStatus = i.Status.ToString(),
ApplicationDate = i.DateSubmitted.ToString(),
ApplicationID = i.ID.ToString(),
};
GridView.DataSource = ApplicationData.ToList();
GridView.DataBind();
}
catch (System.Data.SqlClient.SqlException ex)
{
ErrorMessage.Text = ex.Message.ToString();
}
}
}
protected void OnRowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(ViewApplicationsGrid, "Select$" + e.Row.RowIndex);
e.Row.ToolTip = "Click to select this row.";
}
}

Refresh GridView on click event

Currently I'm working on a webform app and I populate the DevExpress grid on selected value from a ASPxComboBox. I have this part working no problem. However my requirement is to refresh the grid if there is any new data added into the database so the users can see this. So I've added a button and on the click event I try to refresh the data but the grid doesn't refresh. If I step through the code I can see that the new values from the database are there in my DataTable. I can't seem to figure out what could be causing the grid to not refresh. Any help would be highly appreciated.
This is what I have so far
SelectedIndexChangedEvent
protected void TrainingOptions_SelectedIndexChanged(object sender, EventArgs e)
{
ASPxComboBox ddl = (ASPxComboBox)sender;
string[] parameters = { ddl.SelectedItem.Value.ToString() };
TrainingGrid.DataSource = dto.PopulateTrainingData(parameters);
TrainingGrid.DataBind();
}
ButtonClickEvent
protected void Refresh_Click(object sender, EventArgs e)
{
string[] parameters = { TrainingOptions.SelectedItem.Value.ToString() };
TrainingGrid.DataSource = dto.PopulateTrainingData(parameters);
TrainingGrid.DataBind();
}
PopulateTrainingDara
public DataTable PopulateTrainingData(params string[] parameters)
{
//Loop through DataTable Here
...
HttpContext.Current.Session["GridDT"] = mainTable;
return mainTable;
}
DataBinding
protected void TrainingGrid_DataBinding(object sender, EventArgs e)
{
TrainingGrid.DataSource = Session["GridDT"];
}
Page_LoadEvent
if (!IsPostBack)
{
DataTable dropDownOptions = dto.GetTrainingData("MyQuery");
//Add datasource to TrainingOptions dropdown
TrainingOptions.DataSource = dropDownOptions;
TrainingOptions.Text = "Please choose";
TrainingOptions.TextField = "ID";
TrainingOptions.DataBindItems();
}
Markup
<dx:ASPxComboBox ID="TrainingOptions" runat="server" ValueType="System.String" OnSelectedIndexChanged="TrainingOptions_SelectedIndexChanged" CssClass="combo-box"></dx:ASPxComboBox>
<dx:ASPxGridView ID="TrainingGrid" runat="server" OnHtmlDataCellPrepared="TrainingGrid_HtmlDataCellPrepared" OnDataBinding="TrainingGrid_DataBinding"></dx:ASPxGridView>
<dx:ASPxButton ID="Refresh" runat="server" Text="Refresh" OnClick="Refresh_Click" AutoPostBack="false"></dx:ASPxButton>
Note: I am not populating the grid in the Page_Load event.
If any other information is required please let me know.
Ok, so I've recreated your example with the latest trial version of DevExpress Suite. I removed unnecessary code and this is the code that works in my case:
public partial class DevExpress : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable dropDownOptions = new DataTable();
dropDownOptions.Columns.Add("id");
DataRow row = dropDownOptions.NewRow();
row["id"] = 1;
dropDownOptions.Rows.Add(row);
row = dropDownOptions.NewRow();
row["id"] = 2;
dropDownOptions.Rows.Add(row);
dropDownOptions.AcceptChanges();
TrainingOptions.DataSource = dropDownOptions;
TrainingOptions.Text = "Please choose";
TrainingOptions.TextField = "ID";
TrainingOptions.DataBindItems();
}
}
protected void Refresh_Click(object sender, EventArgs e)
{
string[] parameters = { TrainingOptions.SelectedItem.Value.ToString() };
TrainingGrid.DataSource = PopulateTrainingData(parameters);
TrainingGrid.DataBind();
}
protected void TrainingOptions_SelectedIndexChanged(object sender, EventArgs e)
{
ASPxComboBox ddl = (ASPxComboBox)sender;
string[] parameters = { ddl.SelectedItem.Value.ToString() };
TrainingGrid.DataSource = PopulateTrainingData(parameters);
TrainingGrid.DataBind();
}
public DataTable PopulateTrainingData(params string[] parameters)
{
DataTable mainTable = (DataTable)Session["GridDT"] ?? new DataTable();
if (!mainTable.Columns.Contains("id"))
{
mainTable.Columns.Add("id");
}
DataRow row = mainTable.NewRow();
row["id"] = parameters[0];
mainTable.Rows.Add(row);
mainTable.AcceptChanges();
HttpContext.Current.Session["GridDT"] = mainTable;
return mainTable;
}
}
And the aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="DevExpress.aspx.cs" Inherits="WebApplication1.DevExpress" %>
<%# Register Assembly="DevExpress.Web.v15.2, Version=15.2.7.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web" TagPrefix="dx" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<dx:ASPxComboBox ID="TrainingOptions" runat="server" ValueType="System.String" OnSelectedIndexChanged="TrainingOptions_SelectedIndexChanged" AutoPostBack="true" CssClass="combo-box"></dx:ASPxComboBox>
<dx:ASPxGridView ID="TrainingGrid" runat="server"></dx:ASPxGridView>
<dx:ASPxButton ID="Refresh" runat="server" Text="Refresh" OnClick="Refresh_Click"></dx:ASPxButton>
</asp:Content>
If this is not working for you you should check which version of DevExpress controls are you using and maybe update them if its possible. Or maybe you are doing something more which you didn't post here.

call RowDataBound from another function

I have a 2 Gridviews. The first grid has a button that when clicked it will populate a second grid with the data based on the id of the button clicked.
I then have code in the RowDataBound function to show the grid based on the row selected. But the problem is the code is automatically running the RowDataBound before the populate function. So the second grid isn't displaying.
Code for GridView:
<asp:GridView style="width:75%"
ID="gvCVRT"
ShowHeaderWhenEmpty="true"
CssClass="tblResults"
runat="server"
OnRowDataBound="gvCVRT_RowDataBound"
OnSelectedIndexChanged="gridviewParent_SelectedIndexChanged"
DataKeyField="ID"
DataKeyNames="ChecklistID"
AutoGenerateColumns="false"
allowpaging="false"
AlternatingRowStyle-BackColor="#EEEEEE">
<HeaderStyle CssClass="tblResultsHeader" />
<Columns>
<asp:BoundField DataField="ChecklistID" HeaderText="ID" ></asp:BoundField>
<asp:CommandField ShowSelectButton="True" HeaderText="Select" />
<asp:BoundField DataField="ChecklistDate" HeaderText="Checklist Date" dataformatstring="{0:dd/MM/yyyy}"></asp:BoundField>
<asp:BoundField DataField="User" HeaderText="User" ></asp:BoundField>
<asp:BoundField DataField="Note" HeaderText="Note" ></asp:BoundField>
</Columns>
</asp:GridView>
Code behind:
protected void gvCVRT_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
lookupCVRT work = (lookupCVRT)e.Row.DataItem;
GridView gv = sender as GridView;
if (work.ID != null)
{
int index = gv.Columns.HeaderIndex("Select");
if (index > -1)
{
e.Row.Cells[index].Attributes.Add("class", "gvCVRTRow");
e.Row.Cells[index].ToolTip = "Click here to Edit Checklist";
}
}
}
}
Code for select button:
protected void gridviewParent_SelectedIndexChanged(object sender, EventArgs e)
{
List<lookupCVRT> workDetails = lookupCVRT.GetChecklistItemsByChecklistID(Company.Current.CompanyID, ParentID.ToString(), gvCVRT.SelectedDataKey.Value.ToString());
gvCVRTDetails.DataSource = workDetails;
gvCVRTDetails.DataBind();
FireJavascriptCallback("setArgAndPostBack ();");
}
So the problem is when I click on the Select button in the grid it runs the RowDataBound first then the gridviewParent_SelectedIndexChanged but I need to run gridviewParent_SelectedIndexChanged first. Can I call the RowDataBound function from gridviewParent_SelectedIndexChanged?
Page_Load function:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetChecklistID = "";
if (ParentID.HasValue)
{
ViewState["ParentID"] = ParentID;
List<lookupCVRT> work = lookupCVRT.GetCVRTItems(Company.Current.CompanyID, ParentID.ToString());
ViewState["CVRT"] = work;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
List<lookupCVRT> work = ViewState["CVRT"] as List<lookupCVRT>;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
}
The OnRowDataBound event is only called if the DataBind method for the GridView has been called.
In your specific case, the problem is in Page_Load in the else branch of the Page.IsPostBack condition:
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
List<lookupCVRT> work = ViewState["CVRT"] as List<lookupCVRT>;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
This code is run for each postback. Unless you reset ViewState["ParentID"] somewhere else in your code, on every postback you bind the GridView gvCVRT again. This is the reason that RowDataBound is called. After finishing Page_Load, the page calls the additional event handlers, in your case gridviewParent_SelectedIndexChanged.
In order to solve this problem, you need to change the code in your Page_Load handler so that there are no calls to DataBind for a postback:
// field moved to class level so that you can access this variable instead of a DataRow in gvCVRT
private List<lookupCVRT> work;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetChecklistID = "";
if (ParentID.HasValue)
{
ViewState["ParentID"] = ParentID;
work = lookupCVRT.GetCVRTItems(Company.Current.CompanyID, ParentID.ToString());
ViewState["CVRT"] = work;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
work = ViewState["CVRT"] as List<lookupCVRT>;
}
}
}
The root cause of your problem is that you need the data in a postback request and that you put these into ViewState["CVRT"] instead of requesting the data anew. In web applications it is pretty common the read the data again for a new request. So you might think about whether you really need to put the data into ViewState or whether you can request them upon a postback from the data source.
Putting the data into ViewState increases the size of the page that is transferred to the client (basically you have the HTML for the GridView and in addition you have the data in ViewState). So requesting them anew would be the better way in most cases.
I don't know why you preferred to use gridviewParent_SelectedIndexChanged then grdParent_RowDataBound ... i have created a simple solution for you .. it could help you ..
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div>
<label>Parent Grid</label>
<asp:GridView ID="grdParent" runat="server" AutoGenerateColumns="false"
DataKeyField="Id" OnRowDataBound="grdParent_RowDataBound" OnRowCommand="grdParent_RowCommand">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:ButtonField CommandName="Details" HeaderText="Select" Text="Hello" ButtonType="Link" />
</Columns>
</asp:GridView>
</div>
<div>
<label>child Grid</label>
<asp:GridView ID="grdChild" runat="server" AutoGenerateColumns="false"
DataKeyNames="ChildId" OnRowDataBound="grdChild_RowDataBound">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="Roll" />
<asp:ImageField HeaderText="Image" />
</Columns>
</asp:GridView>
</div>
</div>
</form>
</body>
</html>
Codebehind
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<ParentClass> pList = new List<ParentClass>()
{
new ParentClass{Id=5, Name="V"},
new ParentClass{Id=6,Name="VI"},
new ParentClass{Id=7,Name="VII"},
new ParentClass{Id=8,Name="VIII"},
new ParentClass{Id=9,Name="IX"},
new ParentClass{Id=10,Name="X"},
};
grdParent.DataSource = pList;
grdParent.DataBind();
}
}
protected void grdParent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == null || e.Row.RowType != DataControlRowType.DataRow)
{
return;
}
ParentClass p = e.Row.DataItem as ParentClass;
var btn = e.Row.Cells[1].Controls[0] as LinkButton;
btn.CommandArgument = p.Id.ToString();
}
protected void grdParent_RowCommand(object sender, GridViewCommandEventArgs e)
{
int parentId = Convert.ToInt32(e.CommandArgument);
var releventStudents = GetRepositary().FindAll(i => i.ParentId == parentId);
grdChild.DataSource = releventStudents;
grdChild.DataBind();
}
protected void grdChild_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == null || e.Row.RowType != DataControlRowType.DataRow)
{
return;
}
//lookupCVRT work = (lookupCVRT)e.Row.DataItem;
//GridView gv = sender as GridView;
//if (work.ID != null)
//{
// int index = gv.Columns.HeaderIndex("Select");
// if (index > -1)
// {
// e.Row.Cells[index].Attributes.Add("class", "gvCVRTRow");
// e.Row.Cells[index].ToolTip = "Click here to Edit Checklist";
// }
//}
}
private List<ChildClass> GetRepositary()
{
List<ChildClass> allChild = new List<ChildClass>();
Random r = new Random();
for (int i = 0; i < 50; i++)
{
ChildClass c = new ChildClass
{
ChildId = i,
ParentId = r.Next(5, 10),
Name = "Child Name " + i,
Roll = i
};
allChild.Add(c);
}
return allChild;
}
}
public class ParentClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ChildClass
{
public int ParentId { get; set; }
public int ChildId { get; set; }
public int Roll { get; set; }
public string Name { get; set; }
}

GridView client side paging not working

Work with data from other program (for example in this code i use random number array - like query data from other program). Query it to DataTable and bind to GridView + adds for all rows delete button.
On delete button click - this button is inactive (use button.Enabled = false; and UpdatePanel so on buttons click i have "old" array all works great).
But when I use paging - I have "new" array for each time.
How to fix it? I need - in first page i click button - they became inactive, then I choose second page, then return in first page and see "old" array with inactive button.
aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:UpdatePanel ID="Up1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnRowDeleted="GridView1_RowDeleted"
OnRowDeleting="GridView1_RowDeleting" OnDataBinding="GridView1_DataBinding" AllowPaging="true" PageSize="10" OnPageIndexChanging="GridView1_PageIndexChanging">
<Columns>
<asp:BoundField DataField="Name" ItemStyle-Width="200px">
<ItemStyle Width="200px"></ItemStyle>
</asp:BoundField>
<asp:BoundField DataField="Number" ItemStyle-Width="200px">
<ItemStyle Width="200px"></ItemStyle>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button ID="Button2" runat="server" Text="Button" onclick="Button2_Click" OnClientClick="return DeleteConfirm();" />
<asp:HiddenField ID="HiddenField2" runat="server" Value='<%# Bind("Name") %>' />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
<br />
<br />
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Reset" />
</div>
</form>
<script type="text/javascript">
function DeleteConfirm() {
if (confirm("Are you sure you want to delete this customer from excluded customer list ?")) {
return true;
}
return false;
}
</script>
</body>
</html>
aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
private DataTable _Source;
public WebForm1()
{
ResetData();
}
private void ResetData()
{
_Source = new DataTable();
_Source.Columns.Add("Name", typeof(string));
_Source.Columns.Add("Number", typeof(string));
Random rn = new Random();
for (int t = 0; t < 100; t++)
{
_Source.Rows.Add(rn.Next(1, 10).ToString(), rn.Next(1, 10).ToString());
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
GridView1.DataBind();
}
protected void GridView1_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
}
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
_Source.Rows.RemoveAt(e.RowIndex);
//GridView1.DataBind();
Response.Redirect("~/WebForm1.aspx");
}
protected void Button1_Click(object sender, EventArgs e)
{
ResetData();
GridView1.DataBind();
}
protected void GridView1_DataBinding(object sender, EventArgs e)
{
GridView1.DataSource = _Source;
}
protected void Button2_Click(object sender, EventArgs e)
{
var button = sender as Button;
button.Enabled = false;
var hidden = button.Parent.FindControl("HiddenField2") as HiddenField;
var name = hidden.Value;
DeletForName(name);
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
// GridView1.DataSource = _Source;
//GridView1.DataBind();
}
private void DeletForName(string name)
{
foreach (DataRow row in _Source.Rows)
if (row["Name"].Equals(name))
{
_Source.Rows.Remove(row);
break;
}
}
}
}
You basically need to store the data source between requests. One option would be to use the Session variable:
public partial class WebForm1 : System.Web.UI.Page
{
private DataTable _Source;
public WebForm1()
{
}
private void ResetData()
{
_Source = new DataTable();
_Source.Columns.Add("Name", typeof(string));
_Source.Columns.Add("Number", typeof(string));
Random rn = new Random();
for (int t = 0; t < 100; t++)
{
_Source.Rows.Add(rn.Next(1, 10).ToString(), rn.Next(1, 10).ToString());
}
Session["data"] = _Source;
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ResetData();
GridView1.DataBind();
}
_Source = Session["data"] as DataTable;
}
protected void GridView1_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
}
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
((DataTable)Session["data"]).Rows.RemoveAt(e.RowIndex);
}
protected void Button1_Click(object sender, EventArgs e)
{
ResetData();
GridView1.DataBind();
}
protected void GridView1_DataBinding(object sender, EventArgs e)
{
GridView1.DataSource = _Source;
}
protected void Button2_Click(object sender, EventArgs e)
{
var button = sender as Button;
button.Enabled = false;
var hidden = button.Parent.FindControl("HiddenField2") as HiddenField;
var name = hidden.Value;
DeletForName(name);
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
GridView1.DataBind();
}
private void DeletForName(string name)
{
foreach (DataRow row in _Source.Rows)
if (row["Name"].Equals(name))
{
_Source.Rows.Remove(row);
break;
}
}
}
Basically when the page loads, if it is not a post back, it creates a new DataTable and stores it in the Session variable. If it is a post back, it pulls the already existing data from the Session variable. Also, you only want to call your ResetData function when you need to create a new DataTable, so I took it out of the constructor.
Also, be sure the Name column of your actual data source is unique, because your delete function will delete the first row that has the name you are looking for, not necessarily the row you selected for deletion.
Hope this helps!
EDIT
Two possibilities. I think the most likely is that you want to keep the deleted data in the table, but just mark it as deleted and disable its delete button in the gridview. To do this, my instinct is to add a boolean column to the table that indicates whether a row has been deleted or not. Then when a row is databound, check if it has been deleted and the disable the button accordingly:
private void DeletForName(string name)
{
foreach (DataRow row in _Source.Rows)
if (row["Name"].Equals(name))
{
row["Deleted"] = true;
break;
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if ((bool)((System.Data.DataRowView)e.Row.DataItem)["Deleted"])
{
((Button)e.Row.FindControl("Button2")).Enabled = false;
}
}
}
If you want to remove the item from the table but still disable the button at the index of the rows you have deleted, that would be a little more complicated. Let me know if that's the case and I can try to help with that, but it seems more likely the above is what you want.

Controls disappear after pressing the Edit link

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>

Categories

Resources