So I've got a databound grid view within a UpdatePanel.
The idea is that the user can change the data within the gridview then click a save button to update the data within the database.
However in order to know which rows have been changed I have a textChanged event associated with each textbox, but the event isn't being fired.
Here's the ASP code:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<span>To update your poducts simply change the details below and click Save...</span>
<div class="ProductList">
<asp:GridView ID="ProductList" runat="server" AllowPaging="True" AutoGenerateColumns="False"
BackColor="#FFFBD6" BorderColor="#FFCC66" BorderStyle="None" BorderWidth="1px"
CellPadding="3" OnPageIndexChanged="ProductList_PageIndexChanged" OnPageIndexChanging="ProductList_PageIndexChanging"
PagerSettings-Mode="NumericFirstLast" PageSize="5">
<FooterStyle BackColor="White" ForeColor="#990000" />
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:TextBox ID="tbName" AutoPostBack="true" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productName") %>'></asp:TextBox>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Eval("productID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:TextBox ID="tbDesc" AutoPostBack="true" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productDesc") %>' TextMode="MultiLine"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price">
<ItemTemplate>
<asp:TextBox ID="tbPrice" AutoPostBack="true" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productPrice", "{0:C}") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox id="cbDelete" AutoPostBack="true" EnableViewState="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<RowStyle ForeColor="#000066" />
<SelectedRowStyle BackColor="#669999" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="beige" ForeColor="#000066" HorizontalAlign="Left" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
</asp:GridView>
</div>
<div class="ProductListButtons">
<asp:ImageButton AlternateText="Add" ToolTip="Add New Product" Width="30px" Height="30px"
ImageUrl="~/Images/Add.png" ID="AddBtn" runat="server" OnClick="AddBtn_Click" />
<asp:ImageButton ID="DeleteBtn" runat="server" AlternateText="Delete" Height="30px"
ImageUrl="~/Images/delete.png" ToolTip="Delete Selected" Width="30px" OnClick="DeleteBtn_Click" />
<asp:ImageButton AlternateText="Save Changes" ToolTip="Save Changes" Width="30px"
Height="30px" ImageUrl="~/Images/save-icon.png" ID="SaveBtn" runat="server" OnClick="SaveBtn_Click" />
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ProductList" EventName="PageIndexChanged" />
<asp:AsyncPostBackTrigger ControlID="DeleteBtn" EventName="Click" />
</Triggers>
And here's the C#:
using System;
using System.Data;
using BusinessLogicLayer;
using DataAccessLayer.Objects;
using System.Web.UI.WebControls;
public partial class Controls_ProductList : System.Web.UI.UserControl
{
public int StallID { get; set; }
bool[] rowChanged;
bool[] rowDeleted;
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
StallID = Convert.ToInt16(ViewState["StallID"].ToString());
}
int totalRows = ProductList.Rows.Count;
rowChanged = new bool[totalRows];
rowDeleted = new bool[totalRows];
BindList();
ViewState.Add("StallID", StallID);
}
public void BindList()
{
StallHandler handler = new StallHandler();
DataTable productList = handler.GetProductsByID(StallID);
ProductList.DataSource = productList;
ProductList.DataBind();
}
protected void TextBox_TextChanged(object sender, EventArgs e)
{
TextB开发者_开发技巧ox thisTextBox = (TextBox)sender;
GridViewRow thisGridViewRow = (GridViewRow)thisTextBox.Parent.Parent;
int row = thisGridViewRow.RowIndex;
rowChanged[row] = true;
}
protected void cbDelete_CheckedChanged(object sender, EventArgs e)
{
CheckBox thisCheckbox = (CheckBox)sender;
GridViewRow thisGridViewRow = (GridViewRow)thisCheckbox.Parent.Parent;
int row = thisGridViewRow.RowIndex;
rowDeleted[row] = true;
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
ProductList.DataBind();
}
}
protected void ProductList_PageIndexChanged(object sender, EventArgs e)
{
}
protected void ProductList_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
ProductList.PageIndex = e.NewPageIndex;
ProductList.DataBind();
}
protected void AddBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
Response.Redirect("../StallHolder/AddProduct.aspx");
}
protected void DeleteBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
int totalRows = ProductList.Rows.Count;
for (int r = 0; r < totalRows; r++)
{
if (rowDeleted[r])
{
GridViewRow thisGridViewRow = ProductList.Rows[r];
HiddenField hf1 = (HiddenField)thisGridViewRow.FindControl("HiddenField1");
string ID = hf1.Value;
StallHandler handler = new StallHandler();
handler.DeleteProduct(Convert.ToInt16(ID));
}
}
BindList();
}
protected void SaveBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
int totalRows = ProductList.Rows.Count;
for (int r = 0; r < totalRows; r++)
{
if (rowChanged[r])
{
GridViewRow thisGridViewRow = ProductList.Rows[r];
HiddenField hf1 = (HiddenField)thisGridViewRow.FindControl("HiddenField1");
string ID = hf1.Value;
TextBox tbName = (TextBox)thisGridViewRow.FindControl("tbName");
string Name = tbName.Text;
TextBox tbDesc = (TextBox)thisGridViewRow.FindControl("tbDesc");
string Desc = tbDesc.Text;
TextBox tbPrice = (TextBox)thisGridViewRow.FindControl("tbPrice");
string Price = tbPrice.Text;
//Code to update the database!
}
}
}
}
Sorry thats pretty code heavy but I have no idea what I'm doing wrong or where.
Ok, got a couple of things I found when getting this to work. Have a look at the code snippets
ASP:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<span>To update your poducts simply change the details below and click Save...</span>
<div class="ProductList">
<asp:GridView ID="ProductList" runat="server" AllowPaging="True" AutoGenerateColumns="False"
BackColor="#FFFBD6" BorderColor="#FFCC66" BorderStyle="None" BorderWidth="1px"
CellPadding="3" OnPageIndexChanged="ProductList_PageIndexChanged" OnPageIndexChanging="ProductList_PageIndexChanging"
PagerSettings-Mode="NumericFirstLast" PageSize="5">
<FooterStyle BackColor="White" ForeColor="#990000" />
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:TextBox ID="tbName" AutoPostBack="false" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productName") %>'></asp:TextBox>
<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Eval("productID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:TextBox ID="tbDesc" AutoPostBack="false" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productDesc") %>' TextMode="MultiLine"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price">
<ItemTemplate>
<asp:TextBox ID="tbPrice" AutoPostBack="false" EnableViewState="true" runat="server" BorderStyle="None" OnTextChanged="TextBox_TextChanged"
Text='<%# Bind("productPrice", "{0:C}") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox id="cbDelete" OnCheckedChanged="cbDelete_CheckedChanged" AutoPostBack="false" EnableViewState="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<RowStyle ForeColor="#000066" />
<SelectedRowStyle BackColor="#669999" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="beige" ForeColor="#000066" HorizontalAlign="Left" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
</asp:GridView>
</div>
<div class="ProductListButtons">
<asp:ImageButton AlternateText="Add" ToolTip="Add New Product" Width="30px" Height="30px"
ImageUrl="~/Images/Add.png" ID="AddBtn" runat="server" OnClick="AddBtn_Click" />
<asp:ImageButton ID="DeleteBtn" runat="server" AlternateText="Delete" Height="30px"
ImageUrl="~/Images/delete.png" ToolTip="Delete Selected" Width="30px" OnClick="DeleteBtn_Click" />
<asp:ImageButton AlternateText="Save Changes" ToolTip="Save Changes" Width="30px"
Height="30px" ImageUrl="~/Images/save-icon.png" ID="SaveBtn" runat="server" OnClick="SaveBtn_Click" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
And the code-behind:
public partial class Controls_ProductList : System.Web.UI.UserControl
{
public int StallID { get; set; }
bool[] rowChanged;
bool[] rowDeleted;
// this allows me to test your code without your data source (C# 3.0 list constructor)
private static List<Product> _productList = new List<Product>() {
new Product() { productID = 1, productName = "Product 1", productDesc = "This is product 1", productPrice = 1.0m },
new Product() { productID = 2, productName = "Product 2", productDesc = "This is product 2", productPrice = 1.0m },
new Product() { productID = 3, productName = "Product 3", productDesc = "This is product 3", productPrice = 1.0m }
};
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
StallID = Convert.ToInt16(ViewState["StallID"].ToString());
}
else
{
// Only bind if this is not a postback
BindList();
}
int totalRows = ProductList.Rows.Count;
rowChanged = new bool[totalRows];
rowDeleted = new bool[totalRows];
ViewState.Add("StallID", StallID);
foreach (GridViewRow row in ProductList.Rows)
{
var checkBox = row.FindControl("cbDelete");
ScriptManager1.RegisterAsyncPostBackControl(checkBox);
}
}
public void BindList()
{
//StallHandler handler = new StallHandler();
//DataTable productList = handler.GetProductsByID(StallID);
ProductList.DataSource = _productList;
ProductList.DataBind();
}
protected void TextBox_TextChanged(object sender, EventArgs e)
{
TextBox thisTextBox = (TextBox)sender;
GridViewRow thisGridViewRow = (GridViewRow)thisTextBox.Parent.Parent;
int row = thisGridViewRow.RowIndex;
rowChanged[row] = true;
}
protected void cbDelete_CheckedChanged(object sender, EventArgs e)
{
CheckBox thisCheckbox = (CheckBox)sender;
GridViewRow thisGridViewRow = (GridViewRow)thisCheckbox.Parent.Parent;
int row = thisGridViewRow.RowIndex;
rowDeleted[row] = true;
}
protected void Page_PreRender(object sender, EventArgs e)
{
//if (Page.IsPostBack)
//{
// ProductList.DataBind();
//}
}
protected void ProductList_PageIndexChanged(object sender, EventArgs e)
{
}
protected void ProductList_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
ProductList.PageIndex = e.NewPageIndex;
ProductList.DataBind();
}
protected void AddBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
Response.Redirect("../StallHolder/AddProduct.aspx");
}
protected void DeleteBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
int totalRows = ProductList.Rows.Count;
for (int r = 0; r < totalRows; r++)
{
if (rowDeleted[r])
{
GridViewRow thisGridViewRow = ProductList.Rows[r];
HiddenField hf1 = (HiddenField)thisGridViewRow.FindControl("HiddenField1");
int ID = Convert.ToInt16(hf1.Value);
//StallHandler handler = new StallHandler();
//handler.DeleteProduct(Convert.ToInt16(ID));
_productList = _productList.Where(a => a.productID != ID).ToList();
}
}
BindList();
}
protected void SaveBtn_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
int totalRows = ProductList.Rows.Count;
for (int r = 0; r < totalRows; r++)
{
if (rowChanged[r])
{
GridViewRow thisGridViewRow = ProductList.Rows[r];
HiddenField hf1 = (HiddenField)thisGridViewRow.FindControl("HiddenField1");
int ID = Convert.ToInt32(hf1.Value);
TextBox tbName = (TextBox)thisGridViewRow.FindControl("tbName");
string Name = tbName.Text;
TextBox tbDesc = (TextBox)thisGridViewRow.FindControl("tbDesc");
string Desc = tbDesc.Text;
TextBox tbPrice = (TextBox)thisGridViewRow.FindControl("tbPrice");
string Price = tbPrice.Text;
//Code to update the database!
var product = _productList.Where(a => a.productID == ID).First();
product.productName = Name;
product.productDesc = Desc;
product.productPrice = decimal.Parse(Price, System.Globalization.NumberStyles.Currency);
}
}
BindList();
}
}
public class Product
{
public int productID { get; set; }
public string productName { get; set; }
public string productDesc { get; set; }
public decimal productPrice { get; set; }
}
I had to create my own class to use as the data source to test this. Just remove those bits of code for your solution.
As you can see, I've made some changes:
- Set
AutoPostback="False"
for the check box and text boxes. - Removed the
<Triggers>
element, as this only applies to controls outside theUpdatePanel
. - Added the
OnCheckedChanged="cbDelete_CheckedChanged"
element to the check box.
Some minor changes also but none worth mentioning. Although I should mention I'm not a fan of the way you have done this, but it does seem to work.
精彩评论