pictureIf I selected male radio button then different options show in dropdown list if I select Female then show different options in dropdown list with the help of RowDataBound Method.
Ok, in fact much of the trick and issue is that when you load the existing grid of data, we ALSO have to setup the radiobutton choice and the drop down list.
So, say we have this grid:
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" cssclass="table" OnRowDataBound="GHotels_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Gender">
<ItemTemplate>
<asp:RadioButtonList ID="RGender" runat="server"
RepeatDirection="Horizontal"
Text='<%# Eval("Gender") %>' >
<asp:ListItem>M</asp:ListItem>
<asp:ListItem>F</asp:ListItem>
</asp:RadioButtonList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Option">
<ItemTemplate>
<asp:DropDownList ID="cboOption" runat="server"
DataValueField="ID"
DataTextField="Feature" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
Code to load the grid is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GHotels.DataSource = MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName");
GHotels.DataBind();
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
And we now have this:
but, note how we STILL have to load up the radiobutton list and ALSO setup the combo box that gives a different set of choices.
So, we add this code to the row data bound event.
protected void GHotels_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gData = e.Row.DataItem as DataRowView;
// based on Gender fill cbo box
string strSQL = "SELECT ID, Feature FROM tblHotelOptions ";
if (gData["Gender"].ToString() == "M")
{
strSQL += "WHERE Gender = 'M'";
}
else
{
strSQL += "WHERE Gender = 'F'";
}
strSQL += " ORDER BY Feature";
DropDownList cboOption = e.Row.FindControl("cboOption") as DropDownList;
cboOption.DataSource = MyRst(strSQL);
cboOption.DataBind();
cboOption.Items.Insert(0, new ListItem("Select", "0"));
if (gData["HotelOption"] != null)
cboOption.SelectedValue = gData["HotelOption"].ToString();
}
}
So, for each grid row, we process the data row information, and conditional load up the drop down list with choices based on gender.
Now, that works for "loading", but now we need to add the event and code for when we CHANGE the radio button choice.
so, in the markup, we add this event to the radiobutton:
We have to use markup and intel-sense to pop up the choice to create a new event, like this:
So, we added autopostback=true to the radio button list, and the selected change event.
So, now when you change the radio choice, we need to run code to change the drop down list choices.
So, that code can look like this:
protected void RGender_SelectedIndexChanged(object sender, EventArgs e)
{
RadioButtonList rBtn = sender as RadioButtonList;
GridViewRow gRow = rBtn.NamingContainer as GridViewRow;
string strSQL = "SELECT ID, Feature FROM tblHotelOptions ";
if (rBtn.SelectedItem.Text == "M")
// based on Gender fill cbo box
{
strSQL += "WHERE Gender = 'M'";
}
else
{
strSQL += "WHERE Gender = 'F'";
}
strSQL += " ORDER BY Feature";
DropDownList cboOption = gRow.FindControl("cboOption") as DropDownList;
cboOption.DataSource = MyRst(strSQL);
cboOption.DataBind();
cboOption.Items.Insert(0, new ListItem("Select", "0"));
}
In fact, the code is VERY much the same as how we had to load up the grid.
Related
I have a gridview that is being dynamically created based on the database. Some rows of the gridview have 2 DropDownLists, while others do not depending on the item in the row. The second DropDownList of the row is dynamically created based on the selection of the first DrowpDownMenu. Everything works as it should except, if you make the selections on the first row, then change the selection of the first DropDownList of the seccond row or click the update button, it will reset the second DropDownList of the first row. This is obviously due to PostBack. But I'd like to maintain the selection until all DropDownLists have been selected and I save the changes to the DB. Any help would be very appreciated.
My Gridview:
<asp:GridView ID="CartList" runat="server" AutoGenerateColumns="False" ShowFooter="True"
GridLines="Vertical" CellPadding="4" CssClass="table table-striped table-bordered"
OnRowDataBound="CartList_RowDataBound">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ID" SortExpression="ProductID" />
<asp:BoundField DataField="Product.ProductName" HeaderText="Name" />
<asp:BoundField DataField="Product.UnitPrice" HeaderText="Price (each)" DataFormatString="{0:c}" />
<asp:TemplateField HeaderText="Quantity">
<ItemTemplate>
<asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" Text='<%# Eval("Quantity") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:DropDownList ID="Sizeddl" runat="server" Font-Size="Medium"
AutoPostBack="true" ForeColor="Black" OnSelectedIndexChanged="Sizeddl_SelectedIndexChanged">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Color">
<ItemTemplate>
<asp:DropDownList ID="ColorNameddl" runat="server"
Font-Size="Medium" ForeColor="Black">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Item Total">
<ItemTemplate>
<%#: String.Format("{0:c}", ((Convert.ToDouble( Eval("Quantity") )) * Convert.ToDouble(Eval("Product.UnitPrice"))))%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Remove Item">
<ItemTemplate>
<asp:CheckBox ID="Remove" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<div>
<p></p>
<strong>
<asp:Label ID="LabelSubtotal" runat="server" Text="SubTotal: "></asp:Label>
<asp:Label ID="lblSubtotal" runat="server" EnableViewState="false"></asp:Label>
</strong>
<p></p>
<strong>
<asp:Label ID="LabelTax" runat="server" Text="Tax Total: "></asp:Label>
<asp:Label ID="lblTax" runat="server" EnableViewState="false"></asp:Label>
</strong>
<p></p>
<strong>
<asp:Label ID="LabelTotalText" runat="server" Text="Order Total: "></asp:Label>
<asp:Label ID="lblTotal" runat="server" EnableViewState="false"></asp:Label>
</strong>
</div>
<br />
<table>
GridView Load:
DataTable rstSize = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
{
decimal cartTotal = 0;
cartTotal = usersShoppingCart.GetTotal();
if (cartTotal > 0)
{
// Display Total.
lblSubtotal.Text = String.Format("{0:c}", usersShoppingCart.GetSubtotal());
lblTax.Text = String.Format("{0:c}", usersShoppingCart.GetTax());
lblTotal.Text = String.Format("{0:c}", usersShoppingCart.GetTotal());
}
else
{
lblSubtotal.Text = "";
lblTax.Text = "";
lblTotal.Text = "";
ShoppingCartTitle.InnerText = "Shopping Cart is Empty";
UpdateBtn.Visible = false;
CheckoutImageBtn.Visible = false;
}
if (!IsPostBack)
{
LoadGrid();
}
}
}
void LoadGrid()
{
// Load Cart Items.
using (ShoppingCartActions actions = new ShoppingCartActions())
{
var _db = new ProductContext();
string cartId = actions.GetCartId();
var cart = _db.ShoppingCartItems.Where(
c => c.CartId == cartId).ToList();
// Create DataTable for Colors
rstSize.Columns.Add("SizeName", typeof(string));
var row = rstSize.NewRow();
row["SizeName"] = "S";
row["SizeName"] = "M";
row["SizeName"] = "L";
row["SizeName"] = "XL";
row["SizeName"] = "2XL";
CartList.DataSource = cart;
CartList.DataBind();
// Hide DropDown Lists for rows that they are not needed for.
for (int i = 0; i < CartList.Rows.Count; i++)
{
DropDownList sizeDDL = CartList.Rows[i].FindControl("Sizeddl") as DropDownList;
DropDownList colorDDL = CartList.Rows[i].FindControl("ColorNameddl") as DropDownList;
IOrderedDictionary rowValues = new OrderedDictionary();
rowValues = GetValues(CartList.Rows[i]);
var _prodID = Convert.ToInt32(rowValues["ProductID"]);
var _prod = (from c in _db.Products
where c.ProductID == _prodID
select c.CategoryID).FirstOrDefault();
if (_prod != 1)
{
sizeDDL.Visible = false;
colorDDL.Visible = false;
}
}
}
}
My RowDataBound:
protected void CartList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gData = (DataRowView)e.Row.DataItem;
// Populate and select Color from DB.
DropDownList sizeDDL = (DropDownList)e.Row.FindControl("Sizeddl");
sizeDDL.DataSource = rstSize;
sizeDDL.DataBind();
sizeDDL.Items.Insert(0, new ListItem("Select Size", "0"));
sizeDDL.SelectedValue = gData["SizeName"].ToString();
// Load Color DDL
var _size = sizeDDL.SelectedItem.Text;
int _prod = Convert.ToInt32(e.Row.Cells[0].Text);
var _db = new ProductContext();
var qryColor = (from p in _db.ProductAttributes
join c in _db.Colors
on p.ColorID equals c.ColorID
where p.SizeName == _size & p.ProductID == _prod
select new { p.ColorID, c.ColorName }).Distinct().ToList();
DropDownList colorDDL = (DropDownList)e.Row.FindControl("ColorNameddl");
// Create DataTable for Colors
DataTable rstColor = new DataTable();
rstColor.Columns.Add("ColorID", typeof(int));
rstColor.Columns.Add("ColorName", typeof(string));
foreach(var item in qryColor)
{
var row = rstColor.NewRow();
row["ColorID"] = item.ColorID;
row["ColorName"] = item.ColorName;
rstColor.Rows.Add(row);
}
// Bind Color Drop Down List to DataTable.
colorDDL.DataSource = rstColor;
colorDDL.DataBind();
colorDDL.Items.Insert(0, new ListItem("Select Color", "0"));
colorDDL.SelectedValue = gData["ColorName"].ToString();
}
}
My SelectedIndexChanged
protected void Sizeddl_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList sizeDDL = (DropDownList)sender;
GridViewRow gRow = (GridViewRow)sizeDDL.NamingContainer;
string strSize = sizeDDL.SelectedItem.Text;
DropDownList colorDDL = (DropDownList)gRow.FindControl("ColorNameddl");
if (strSize != "Choose one")
{
using (ProductContext context = new ProductContext())
{
int _prodID = Convert.ToInt32(gRow.Cells[0].Text);
var _size = sizeDDL.SelectedItem.Text;
var qryColor = (from p in context.ProductAttributes
join c in context.Colors
on p.ColorID equals c.ColorID
where p.SizeName == _size & p.ProductID == _prodID
select new { p.ColorID, c.ColorName }).Distinct().ToList();
if (qryColor.Count > 0)
{
colorDDL.DataSource = qryColor;
colorDDL.DataTextField = "ColorName";
colorDDL.DataValueField = "ColorID";
colorDDL.DataBind();
colorDDL.Items.Insert(0, new ListItem("Select Color", "0"));
colorDDL.Enabled = true;
}
else
{
colorDDL.Items.Clear();
colorDDL.Items.Insert(0, new ListItem("No Colors Available", "0"));
colorDDL.Enabled = false;
}
}
}
}
if you make the selections on the first row
By "selections" are we to assume make changes - or select/change a value in the combo boxes, right?
I'd like to maintain the selection until all DropDownLists have been selected and I save the changes to the DB. Any help would be very appreciated.
A grid view will and should handle post backs on the page. After all, even outside of the GV, any old button or control can and will cause post-backs.
There is no reason that changes to ANY grid row by users, and that includes drop down lists (DDL) should matter. And operations on one row should not effect operations on other rows. The so called "view" state of the GV is automatic, and for the most part you should not have to worry.
So, it not at all clear why you posted the "add row", since all of this question centers on editing or making changes to the current row. (for us, say next week or when ever, we can look at or deal with the row created, but for now lets concentrate on the changes to a given row, and why for some reason you see effects in other rows - you should not be seeing this.
Tops on the list?
While controls - including a GV can and should handle post-backs without issue?
That is NOT the case if a post-back causes a re-bind of the grid. If that is to occur, then you going have issues.
So, tops on the list?
You left out how/when/where you are loading up the GV.
(the MOST important part!!!!).
Next up?
You do NOT want nor need to show the row PK id in the GV. These numbers not only mean nothing to the end user but it also a security risk - PK row numbers don't need to be displayed, and in fact do not even need to be included in the row markup. We again can leave that issue for another day, but you can (and should consider) using DataKeys for the row PK id operations. We assume no duplicate PK row id in the database, right? In other words, make sure you have a database row PK "id" in your data.
So, you can in the future, remove that ProductID. GV has a special feature for dealing with the PK row id - and we should be using that. (Datakeys)
Ok, now that we cleared up the above?
In the page load event, we need to load the GV, but ONLY on first page load - after that, we can't re-load the GV (bind again), else you WILL lose your changes, and edits to the GV.
Also, you might want to consider a save button at the bottom - to save all gv changes - in place of doing this row by row. (but, one thing at a time here).
So first up, the code to load the GV, should be in page load.
Next up, that code has to ONLY run the first time.
eg:
if (!IsPostBack)
{
code here to load GV
}
Next up? when the GV is loaded with that data, you need to setup the combo box and the cascade. And further more, this setup of each row should occur in the row data bound event.
So, your posted code does look ok, but we missing how/when you load the GV.
And we don't see your save button either. But at this point, I would share your code that loads up the GV - this all important information is missing here.
So edit your question - show how and when you load the grid up - that's missing.
Also, why the row created event being used here to setup a event? Just put the event stub and definition in the markup.
You are free to drop in a plane jane button, or DDL or whatever into the GV. And you should wire up the events like all other controls.
So, remove that row created event stub - it might be wiring up events for the wrong row - but it not required, and is a high risk adventure.
So, just do this:
So, for a button, or DDL in the GV? You can't double click on a button (to create a click event), and you can't display the property sheet to add events. But you can in markup just type in the event name, hit "=", and note how above intel-sense pops up a option to create the event. So, add the event that way. And after you select create new event, then you can flip over to code behind - you see the new event stub, and add your code to that stub. The GV uses internal information to wire up each row events - you may well be messing this up.
So, I would remove your row added - as we don't have details about that code and how/when you add a row, but 100% elimination of the row created event, and wiring up a click event will go a long way to elimination of any issues here - this would be especially the case if your row add event "copy's" controls - you might be copy the the DDL object when you do this, and that again will cause issues. In other words you may have the same object for two rows - changes to one will effect the other.
So, dump your row add event, and add the event directly in markup for the ddl as per above.
So, for buttons on each row, or whatever? You can still (and should) use markup to add those events - not code unless no other means exists to do so.
Edit: Working example
So, say this markup:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID"
CssClass="table"
Width="30%" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="Firstname" HeaderText="Firstname" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField HeaderText="Select Hotel City">
<ItemTemplate>
<asp:DropDownList ID="cboCity" runat="server" Width="120px" Height="26px"
DataTextField = "City"
DataValueField = "City"
AutoPostback="true"
OnSelectedIndexChanged="cboCity_SelectedIndexChanged"
>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Select Hotel">
<ItemTemplate>
<asp:DropDownList ID="cboHotels" runat="server" Width="210px" Height="26px"
DataValueField ="ID"
DataTextField ="HotelName">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Nights" >
<ItemTemplate>
<asp:TextBox ID="txtNights" runat="server" Style="text-align:right"
Text='<%# Eval("Nights") %>' Width="70px" >
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
We will cascade city combo to restrict Hotels in 2nd combo.
So, our code to load:
DataTable rstCity = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid ()
{
// load up City list for combo box - all rows (scope = page)
SqlCommand cmdSQL = new SqlCommand("SELECT City from City ORDER BY City");
rstCity = MyRstP(cmdSQL);
// load up the grid
cmdSQL.CommandText = "SELECT * from People ORDER BY FirstName";
GridView1.DataSource = MyRstP(cmdSQL);
GridView1.DataBind();
}
We have this:
Note how we did NOT risk trying to set the DDL's in the markup - since we cascading - there will be way too many issues.
So, of course we have row data bound - and that sets up the two DDL's. (we setup the cascade AND ALSO set their values.
We have this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gData = (DataRowView)e.Row.DataItem; // get the row data
// load the city combo box
DropDownList cboCity = (DropDownList)e.Row.FindControl("cboCity");
cboCity.DataSource = rstCity;
cboCity.DataBind();
// add blank row for city
cboCity.Items.Insert(0, new ListItem("Select City", ""));
cboCity.SelectedValue = gData["City"].ToString(); // set value of Current city
// now load Hotel combo box - but cascade from above City cbo
string strSQL = #"Select ID, HotelName From tblHotels WHERE City = #City " +
" ORDER BY HotelName";
SqlCommand cmdSQL = new SqlCommand(strSQL);
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = gData["HotelCity"].ToString();
DropDownList cboHotels = (DropDownList)e.Row.FindControl("cboHotels");
DataTable rstHotels = MyRstP(cmdSQL);
cboHotels.DataSource = rstHotels;
cboHotels.DataBind();
cboHotels.Items.Insert(0, new ListItem("Select Hotel", ""));
// set hotels combo to current selected
cboHotels.SelectedValue = gData["Hotel_id"].ToString();
}
}
So, the only part left is the first DDL post-back and cascade code. We have this:
protected void cboCity_SelectedIndexChanged(object sender, EventArgs e)
{
// city changed, so cascade Hotel cbo
DropDownList cboCity = (DropDownList)sender;
GridViewRow gRow = (GridViewRow)cboCity.NamingContainer;
// filter hotels to current city
string strCity = cboCity.SelectedItem.Text;
DropDownList cboHotels = (DropDownList)gRow.FindControl("cboHotels");
if (strCity != "Select City")
{
SqlCommand cmdSQL = new
SqlCommand(#"SELECT * from tblHotels WHERE City = #City ORDER BY HotelName");
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = strCity;
cboHotels.DataSource = MyRstP(cmdSQL);
cboHotels.DataBind();
cboHotels.Items.Insert(0, new ListItem("Select Hotel", ""));
}
}
So, with above? I don't see how it is possible that some "other" row gets effected here (unless you have some other code that attempts to mess around with the rows, or inserts a row into the GV. If you going to insert a row, then insert at the database level - and re-bind the GV. But, inserting is a separate issue.
So here's the update where the second dropdown now functions correctly. However, when you click the update button, it will save correctly to the DB, but resets and clears out the second drowpdown list.
Markup:
<asp:GridView ID="CartList" runat="server" AutoGenerateColumns="False" ShowFooter="True" GridLines="Vertical" CellPadding="4"
ItemType="GetAGrip.Models.CartItem" CssClass="table table-striped table-bordered"
EnableViewState="true">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ID" SortExpression="ProductID" />
<asp:BoundField DataField="Product.ProductName" HeaderText="Name" />
<asp:BoundField DataField="Product.UnitPrice" HeaderText="Price (each)" DataFormatString="{0:c}" />
<asp:TemplateField HeaderText="Quantity">
<ItemTemplate>
<asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" Text="<%#: Item.Quantity %>"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:DropDownList ID="Sizeddl" runat="server" Font-Size="Medium" OnSelectedIndexChanged="Sizeddl_SelectedIndexChanged"
AutoPostBack="true" ForeColor="Black" SelectedValue="<%#: Item.SizeName %>">
<asp:ListItem Selected="True" Text="Choose one" Value="0"></asp:ListItem>
<asp:ListItem Text="S" Value="S"></asp:ListItem>
<asp:ListItem Text="M" Value="M"></asp:ListItem>
<asp:ListItem Text="L" Value="L"></asp:ListItem>
<asp:ListItem Text="XL" Value="XL"></asp:ListItem>
<asp:ListItem Text="2XL" Value="2XL"></asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Color">
<ItemTemplate>
<asp:DropDownList ID="ColorNameddl" runat="server" Font-Size="Medium" ForeColor="Black">
</asp:DropDownList>
<asp:Label ID="Templbl" runat="server" Visible="false" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Item Total">
<ItemTemplate>
<%#: String.Format("{0:c}", ((Convert.ToDouble(Item.Quantity)) * Convert.ToDouble(Item.Product.UnitPrice)))%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Remove Item">
<ItemTemplate>
<asp:CheckBox ID="Remove" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<div>
<p></p>
<strong>
<asp:Label ID="LabelSubtotal" runat="server" Text="SubTotal: "></asp:Label>
<asp:Label ID="lblSubtotal" runat="server" EnableViewState="false"></asp:Label>
</strong>
<p></p>
<strong>
<asp:Label ID="LabelTax" runat="server" Text="Tax Total: "></asp:Label>
<asp:Label ID="lblTax" runat="server" EnableViewState="false"></asp:Label>
</strong>
<p></p>
<strong>
<asp:Label ID="LabelTotalText" runat="server" Text="Order Total: "></asp:Label>
<asp:Label ID="lblTotal" runat="server" EnableViewState="false"></asp:Label>
</strong>
</div>
<br />
<table>
<tr>
<td>
<asp:Button ID="UpdateBtn" runat="server" Text="Update" OnClick="UpdateBtn_Click" Visible="false" Enabled="false"/>
</td>
<th colspan="1"> 
</th>
<td>
<asp:ImageButton ID="CheckoutImageBtn" runat="server"
ImageUrl="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif"
Width="145" AlternateText="Check out with PayPal"
OnClick="CheckoutBtn_Click"
BackColor="Transparent" BorderWidth="0" />
</td>
</tr>
</table>
Page_Load
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadGrid();
}
using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
{
decimal cartTotal = 0;
cartTotal = usersShoppingCart.GetTotal();
if (cartTotal > 0)
{
// Display Total.
lblSubtotal.Text = String.Format("{0:c}", usersShoppingCart.GetSubtotal());
lblTax.Text = String.Format("{0:c}", usersShoppingCart.GetTax());
lblTotal.Text = String.Format("{0:c}", usersShoppingCart.GetTotal());
}
else
{
lblSubtotal.Text = "";
lblTax.Text = "";
lblTotal.Text = "";
ShoppingCartTitle.InnerText = "Shopping Cart is Empty";
UpdateBtn.Visible = false;
CheckoutImageBtn.Visible = false;
}
}
}
Load Grid, Load Second DropDown List & Hide DDLs on rows they shouldn't be on:
void LoadGrid()
{
GetShoppingCartItems();
CartList.DataSource = GetShoppingCartItems();
CartList.DataBind();
var _db = new ProductContext();
for (int i = 0; i < CartList.Rows.Count; i++)
{
DropDownList sizeDDL = CartList.Rows[i].FindControl("Sizeddl") as DropDownList;
DropDownList colorDDL = CartList.Rows[i].FindControl("ColorNameddl") as DropDownList;
var _colors = (from c in _db.Colors
select c.ColorName).Distinct().ToList();
colorDDL.DataSource = _colors;
colorDDL.DataBind();
colorDDL.Items.Insert(0, new ListItem("Select Color", "0"));
colorDDL.SelectedIndex = 0;
foreach (ListItem item in colorDDL.Items)
{
item.Attributes.Add("disabled", "disabled");
}
IOrderedDictionary rowValues = new OrderedDictionary();
rowValues = GetValues(CartList.Rows[i]);
var _prodID = Convert.ToInt32(rowValues["ProductID"]);
var _prod = (from c in _db.Products
where c.ProductID == _prodID
select c.CategoryID).FirstOrDefault();
if (_prod != 1)
{
sizeDDL.Visible = false;
colorDDL.Visible = false;
}
}
}
GetShoppingCartItems Method:
public List<CartItem> GetShoppingCartItems()
{
ShoppingCartActions actions = new ShoppingCartActions();
return actions.GetCartItems();
}
UpdateCartItems Method
public List<CartItem> UpdateCartItems()
{
using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
{
String cartId = usersShoppingCart.GetCartId();
ShoppingCartActions.ShoppingCartUpdates[] cartUpdates = new ShoppingCartActions.ShoppingCartUpdates[CartList.Rows.Count];
for (int i = 0; i < CartList.Rows.Count; i++)
{
IOrderedDictionary rowValues = new OrderedDictionary();
rowValues = GetValues(CartList.Rows[i]);
cartUpdates[i].ProductId = Convert.ToInt32(rowValues["ProductID"]);
CheckBox cbRemove = new CheckBox();
cbRemove = (CheckBox)CartList.Rows[i].FindControl("Remove");
cartUpdates[i].RemoveItem = cbRemove.Checked;
TextBox quantityTextBox = new TextBox();
quantityTextBox = (TextBox)CartList.Rows[i].FindControl("PurchaseQuantity");
cartUpdates[i].PurchaseQuantity = Convert.ToInt16(quantityTextBox.Text.ToString());
DropDownList sizeDropDown = new DropDownList();
sizeDropDown = (DropDownList)CartList.Rows[i].FindControl("Sizeddl");
cartUpdates[i].SizeName = sizeDropDown.Text;
DropDownList colorDropDown = new DropDownList();
colorDropDown = (DropDownList)CartList.Rows[i].FindControl("ColorNameddl");
cartUpdates[i].ColorName = colorDropDown.Text;
}
usersShoppingCart.UpdateShoppingCartDatabase(cartId, cartUpdates);
CartList.DataBind();
lblSubtotal.Text = String.Format("{0:c}", usersShoppingCart.GetSubtotal());
lblTax.Text = String.Format("{0:c}", usersShoppingCart.GetTax());
lblTotal.Text = String.Format("{0:c}", usersShoppingCart.GetTotal());
return usersShoppingCart.GetCartItems();
}
}
GetValues Dictionary
public static IOrderedDictionary GetValues(GridViewRow row)
{
IOrderedDictionary values = new OrderedDictionary();
foreach (DataControlFieldCell cell in row.Cells)
{
if (cell.Visible)
{
// Extract values from the cell.
cell.ContainingField.ExtractValuesFromCell(values, cell, row.RowState, true);
}
}
return values;
}
Update Button Click
protected void UpdateBtn_Click(object sender, EventArgs e)
{
for (int i = 0; i < CartList.Rows.Count; i++)
{
UpdateCartItems();
}
Page.Response.Redirect(Page.Request.Url.ToString(), true);
}
RowDataBound
protected void CartList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gData = (DataRowView)e.Row.DataItem; // get row data.
// load the color Drop Down List.
DropDownList sizeDDL = (DropDownList)e.Row.FindControl("Sizeddl");
sizeDDL.SelectedValue = gData["SizeName"].ToString();
//// Load Color DDL
var _size = sizeDDL.SelectedItem.Text;
int _prod = Convert.ToInt32(e.Row.Cells[0].Text);
var _db = new ProductContext();
var qryColor = (from p in _db.ProductAttributes
join c in _db.Colors
on p.ColorID equals c.ColorID
where p.SizeName == _size & p.ProductID == _prod
select new { p.ColorID, c.ColorName }).Distinct().ToList();
DropDownList colorDDL = (DropDownList)e.Row.FindControl("ColorNameddl");
// Bind Color Drop Down List to DataTable.
foreach (ListItem item in colorDDL.Items)
{
if (qryColor.Any(c => c.ColorName == item.ToString()))
{
item.Enabled = true;
}
}
colorDDL.SelectedValue = gData["ColorName"].ToString();
}
}
1st Dropdown SelectedIndexChanged
protected void Sizeddl_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList sizeDDL = (DropDownList)sender;
GridViewRow gRow = (GridViewRow)sizeDDL.NamingContainer;
string strSize = sizeDDL.SelectedItem.Text;
DropDownList colorDDL = (DropDownList)gRow.FindControl("ColorNameddl");
if (strSize != "Choose one")
{
using (ProductContext context = new ProductContext())
{
int _prodID = Convert.ToInt32(gRow.Cells[0].Text);
var _size = sizeDDL.SelectedItem.Text;
var qryColor = (from p in context.ProductAttributes
join c in context.Colors
on p.ColorID equals c.ColorID
where p.SizeName == _size & p.ProductID == _prodID
select new { p.ColorID, c.ColorName }).Distinct().ToList();
if (qryColor.Count > 0)
{
foreach (ListItem item in colorDDL.Items)
{
if (qryColor.Any(c => c.ColorName == item.ToString()))
{
item.Enabled = true;
}
else
{
item.Enabled = false;
}
}
colorDDL.Items[0].Enabled = true;
colorDDL.Enabled = true;
colorDDL.SelectedIndex = 0;
}
else
{
colorDDL.SelectedIndex = 0;
colorDDL.Enabled = false;
}
}
}
}
Anyplace you see a method that is not above, it's because it's a method in my Logic file to handle database queries for the whole application.
I have a gridview showing academy name and a dropdown list. The dropdown list have value of 0-13, 0 is the "Please select option". I want when the save button it skip those row where there is no selection in the dropdown therefore 0.
Here is my code for the gridview:
<asp:GridView ID="gdvAcadSelec" runat="server" AutoGenerateColumns="False"
DataKeyNames="acad_Id"
DataSourceID="srcAcademy"
OnRowDataBound="gdvAcadSelec_RowDataBound"
CssClass="table table-striped table-bordered"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="acad_Id" HeaderText="Id" />
<asp:BoundField DataField="acad_name" HeaderText="Academy" />
<asp:TemplateField HeaderText="Choice">
<ItemTemplate>
<asp:DropDownList ID="ddlPref" OnTextChanged="ddlPref_TextChanged" AutoPostBack="true" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="btnsubmit" CssClass="btn btn-info" OnClick="btnsubmit_Click" runat="server" Text="Submit" />
<asp:ObjectDataSource ID="srcAcademy"
TypeName="dataAccessLayer"
SelectMethod="getAcademy"
runat="server" />
The code behind for the binding of item for the column Choice:
protected void gdvAcadSelec_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Find the DropDownList in the Row
DropDownList ddlCountries = (e.Row.FindControl("ddlPref") as DropDownList);
ddlCountries.Items.Insert(0, new ListItem("Please select"));
ddlCountries.Items.Insert(1, new ListItem("1"));
ddlCountries.Items.Insert(2, new ListItem("2"));
ddlCountries.Items.Insert(3, new ListItem("3"));
ddlCountries.Items.Insert(4, new ListItem("4"));
ddlCountries.Items.Insert(5, new ListItem("5"));
ddlCountries.Items.Insert(6, new ListItem("6"));
ddlCountries.Items.Insert(7, new ListItem("7"));
ddlCountries.Items.Insert(8, new ListItem("8"));
ddlCountries.Items.Insert(9, new ListItem("9"));
ddlCountries.Items.Insert(10, new ListItem("10"));
ddlCountries.Items.Insert(11, new ListItem("11"));
ddlCountries.Items.Insert(12, new ListItem("12"));
ddlCountries.Items.Insert(13, new ListItem("13"));
}
On click save button:
protected void btnsubmit_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in gdvAcadSelec.Rows)
{
DropDownList ddlorder = (DropDownList)row.FindControl("ddlPref");
string acadID = row.Cells[0].Text;
string order = ddlorder.SelectedValue.ToString();
SqlCommand scmd = new SqlCommand();
scmd.CommandType = CommandType.Text;
scmd.CommandText = "Insert into tblAcademy_Selection (acad_Id,stud_Id,order_preference) values (#acad,#stud,#order)";
scmd.Connection = con;
scmd.Parameters.AddWithValue("#acad", acadID);
scmd.Parameters.AddWithValue("#stud", 60);
scmd.Parameters.AddWithValue("#order", order);
con.Open();
scmd.ExecuteNonQuery();
con.Close();
}
}
The problem with this code is when it is saving to the database ,those dropdowns list who have value "please select" is also being save and this crash my website.
What can I do to skip those dropdown that do not have value selected?
Thank you in advance.
(Edited per request from OP)
Simply use an if() statement to skip the values you don't want to insert.
string order = ddlorder.SelectedIndex.ToString();
if (order != "0") { // Some may argue that it should be !order.equals("0") but in C# it doesn't matter.
SqlCommand scmd = new SqlCommand();
scmd.CommandType = CommandType.Text;
.
.
}
And if you're a prudent (and paranoid) programmer, you won't trust anything sent from the browser, you'll check to make sure the variable order is the appropriate type and is within the range of values you expect as well.
My listbox is selecting the values correctly, but it is separating the values per listbox instead of inserting all of the values in one list box.
Why is this behavior happening?
Code Behind
protected void GvInBlocks_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
List<string> list = new List<string>();
//Find listBoxCourse in GvChildBlock
ListBox listBoxCourse = e.Row.FindControl("listBoxCourse") as ListBox;
getCourseLB(listBoxCourse);
//Fill control
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
list.Add(CourseNames);
foreach(ListItem items in listBoxCourse.Items)
{
if(list.Contains(items.Value))
{
items.Selected = true;
}
}
}
}
MarkUp Language
<asp:Panel ID="pnlInBlocks" runat="server" Style="display: none">
<asp:GridView ID="GvInBlocks" runat="server" AutoGenerateColumns="false" CssClass="list" OnRowDataBound="GvInBlocks_RowDataBound">
<Columns>
<asp:TemplateField HeaderText = "Curso">
<ItemTemplate>
<asp:Label ID="lblChildBlockCourse" runat="server" Text='<%# Eval("CourseID") %>' Visible = "false" />
<asp:ListBox ID="listBoxCourse" runat="server" SelectionMode="Multiple">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:Panel>
EDIT:
I edited the code and I did separate the values by a comma but the results remain the same , is it because of the RowDataBound? If the database returns 2 rows is it going to return 2 list boxes?
Code Edited:
//Find listBoxCourse in GvChildBlock
ListBox listBoxCourse = e.Row.FindControl("listBoxCourse") as ListBox;
getCourseLB(listBoxCourse);
//Fill control
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
string[] arrayNames = CourseNames.Split(',');
foreach(var names in arrayNames)
{
listBoxCourse.Items.FindByValue(names).Selected = true;
}
So the course list is like say:
Physics 204, Math 220, Computing 220
So, then you need to split above into a "list" for the listbox
eg:
//Fill control
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
CourseNames = CourseNames.Repace(", ",","); ' remove blanks
List<string> slCourse = (List<string>)CourseNames.Split(',').ToList();
listBoxCourse.DataSource = slCourse;
listBoxCourse.DataBind();
Now, your list box is filled up with values.
Or is there a 100% separate list of choices that supposed to drive the listbox, and you only want to select/set ONE course name as the selected value in listbox?
Ok, for some VERY strange design, we should have this setup:
You have some students, a table of the coures they are taking, and the 3rd table is really just a list of all courses.
but, for some strange reason, we don't have the courses table, and have this:
Worse, we some how have "one" column that has the list of "id" the student is taking (again, breaks every rule - makes ANY kind of solution very difficult).
And even worse yet? The desired output is to display ALL courses for each row, and ONLY highlight the one the student is enrolled.
Seems to me that that each row should ONLY show their courses, and not all of them, and then in that list show the highlighted ones.
But, lets go with this "VERY strange from another planet question that does not make sense to do it this way.
So, we have to fill up the grid, (easy). We also have to drop in a listbox of ALL COURSES.
So, lets do this part first, and THEN we work on the highlight part.
So, we have this grid - a few columns, and list box
<div style="width:40%;padding:35px">
<asp:GridView ID="GVStudents" runat="server" CssClass="table" AutoGenerateColumns="False"
DataKeyNames="ID" OnRowDataBound="GVStudents_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="CourseIDList" HeaderText="CourseIDList" />
<asp:TemplateField HeaderText="Courses" HeaderStyle-Width="190px">
<ItemTemplate>
<asp:ListBox ID="LstCourses" runat="server" Style="Height:120px;width:170px"
DataValueField ="ID"
DataTextField ="Course">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
Ok, now the code to fill this up:
public partial class StudentListBox1 : System.Web.UI.Page
{
DataTable rstCourses = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
rstCourses = MyRst("SELECT ID, Course from Courses ORDER BY Course");
// load grid
GVStudents.DataSource = MyRst("SELECT * FROM Students Order by FirstName");
GVStudents.DataBind();
}
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection con = new SqlConnection(Properties.Settings.Default.TEST4))
using (SqlCommand cmdSQL = new SqlCommand(strSQL, con))
{
con.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
And now out output is this:
So the next bit of code would be to take that id list from that one column, and high light the courses in the course listbox. (and if that works, then we can remove the "id list" row in that grid. So, lets write that part to highlight the courses.
The code would/could be:
(we add right after the databind code that filled the listbox.
So we now from above have this:
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
// get "item list" column (we NOT use from grid, since we plan to remove
// from grid display - so, get this from the data source
DataRowView gData = (DataRowView)e.Row.DataItem;
List<string> sIdList = gData["CourseIDList"].ToString().Split(' ').ToList();
foreach (ListItem lBox in lv.Items)
{
lBox.Selected = sIdList.Contains(lBox.Value);
}
}
}
And now we have this output:
Now, it does seem to me, it would be better to show JUST the courses they have in each list box.
On the other hand, I suppose we could start using the above to tick off (select more courses for each user). And we could use the above grid for this.
Edit ===========================================
Ok, so we now have more information and that each row DOES NOT have a list of courses as "id" separated by some delimited.
so, we can dump the id list list column, and now have just student information in the one line + a list box of courses like this:
<asp:GridView ID="GVStudents" runat="server" CssClass="table" AutoGenerateColumns="False"
DataKeyNames="ID" OnRowDataBound="GVStudents_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField HeaderText="Courses" HeaderStyle-Width="190px">
<ItemTemplate>
<asp:ListBox ID="LstCourses" runat="server" Style="Height:120px;width:170px"
DataValueField ="ID"
DataTextField ="Course"
SelectionMode="Multiple"
SelectMethod="">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And now our code to fill out the list box becomes this:
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
// now get all courses for this student
DataRowView gData = (DataRowView)e.Row.DataItem;
int StudentPK = (int)gData["ID"];
DataTable rstStudentCourses;
string strSQL = "SELECT Course_ID FROM StudentCourses WHERE Student_ID = " + StudentPK;
rstStudentCourses = MyRst(strSQL);
foreach (ListItem lBox in lv.Items)
{
string sFind = "Course_ID = " + lBox.Value;
lBox.Selected = (rstStudentCourses.Select(sFind).Count() > 0);
}
}
And out output is this:
As noted, it might be better for each row to ONLY show the courses taken, and not just highlight out of ALL possible courses.
Of course this is a easy change, and we would DUMP the global scoped courses datatable, and simple pull course list for each row, and directly fill the list box with those courses (it would be less code, since no matching loop against the whole course list in the list box would now be required. (but just query to fill listbox with ONLY courses for the one row/student).
Here is my problem. I have this Grid:
<asp:GridView runat="server" ID="gvTest" AutoGenerateColumns="false" DataKeyNames="IdTask" AllowPaging="true" PageSize="4"
OnPageIndexChanging="gvTest_PageIndexChanging" PagerStyle-CssClass="pagerGrid" CssClass="gvTest" HeaderStyle-CssClass="headerGrid"
RowStyle-CssClass="rowsGrid" OnRowCommand="gvTest_RowCommand" OnRowDataBound="gvTest_RowDataBound">
<Columns>
<asp:BoundField DataField="IdTask" HeaderText="ID" />
<asp:BoundField DataField="Name" HeaderText="Task" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="State" HeaderText="State" />
<asp:BoundField DataField="User" HeaderText="User" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnLoad" runat="server" Text="Bugs" CssClass="btn" data-task-id='<%# Eval("IdTask") %>'></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnProgress" runat="server" Text="TakeInProgress" CommandName="progress" CommandArgument='<%# ((GridViewRow) Container).RowIndex %>'></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="btnFiles" CssClass="btnFiles" runat="server" ImageUrl="img/files.png.png"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
All values come from a mysql database. In the database i have multiple tables but the ones relevant to this problem are:
tasks table : idtask,iduser,name,description
stages table : idstage, idtask, idstate //the connection table
states table: idstate, name
Ok so in the states table i have only 3 : inWaiting, inProgress, Finished
As you can see in the state column of the grid populates each task with its respective state .. the row is colored in red when button is clicked and hide the button once the state becames inProgress
Here is what the codebehind looks like and what i have tried, i only managed to color the row hide button and update the state to inProgress:
protected void gvTest_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "progress")
{
int index = Convert.ToInt32(e.CommandArgument); //converts the row index stored in command argument property to an integer
GridViewRow row = gvTest.Rows[index]; //retrieve the row that contains the button clicked by the user from the rows collection
string state = (row.Cells[3].Text); //gets the value of the cell
int id = Convert.ToInt32(gvTest.DataKeys[row.RowIndex].Value.ToString()); //gets the primary key value
string sqlUpdateState = "UPDATE states SET IdState=#IdState WHERE IdTask = #IdTask";
MySqlCommand cmd = new MySqlCommand(sqlUpdateState, conn);
cmd.Parameters.AddWithValue("#IdTask", id);
cmd.Parameters.AddWithValue("#IdState", 1);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
LoadGridData();
}
}
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string state = (e.Row.Cells[3].Text);
foreach (TableCell cell in e.Row.Cells)
{
if (state == "inProgress")
{
cell.BackColor = Color.Red;
e.Row.Cells[5].Controls.Clear();
}
}
}
}
What i need now is that only a task can be inProgress at a time .. something like if I clicked the button on another row the previous state which was inProgress to change its state to inWaiting and the new task becames inProgress
Can you help?
I tried to explain it as best i could .. english is not my primary language. If you have any questions please ask. Thank you
What I can understand is, you want single task at a time to be 'in progress'.
You can update the state of a task which is 'in progress' to 'in waiting' when changing other task's state to 'in Progress'.
Try this code.
protected void gvTest_RowCommand (object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "progress")
{
int index = Convert.ToInt32(e.CommandArgument); //converts the row index stored in command argument property to an integer
GridViewRow row = gvTest.Rows[index]; //retrieve the row that contains the button clicked by the user from the rows collection
string state = (row.Cells[3].Text); //gets the value of the cell
int id = Convert.ToInt32(gvTest.DataKeys[row.RowIndex].Value.ToString()); //gets the primary key value
string sqlChangeStateToWaiting = "UPDATE task set IDState = #IdState where IDState = #IdStateInProgress";
MySqlCommand cmdChangeStateToWaiting = new MySqlCommand(sqlUpdateState, conn);
cmdChangeStateToWaiting.Parameters.AddWithValue("#IdState ", "id for in waiting");
cmdChangeStateToWaiting.Parameters.AddWithValue("#IdStateInProgress", "id for in progress");
string sqlUpdateState = "UPDATE task SET IdState=#IdState WHERE IdTask = #IdTask";
MySqlCommand cmd = new MySqlCommand(sqlUpdateState, conn);
cmd.Parameters.AddWithValue("#IdTask", id);
cmd.Parameters.AddWithValue("#IdState", 1);
conn.Open();
cmdChangeStateToWaiting.ExecuteNonQuery();
cmd.ExecuteNonQuery();
conn.Close();
LoadGridData();
}
}
I am now stuck. After spending ages trying to maintain dynamically added linkbutton or label to a gridview it seems I am overwriting a checkbox state on post back.
As stated I am dynamically adding either a linkbutton or a label to a place holder in a gridview with the following:
protected void LedgerGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int index = e.Row.RowIndex;
if (items[index].noteID > 0)
{
PlaceHolder label = (PlaceHolder)e.Row.FindControl("HasPrevious");
LinkButton link = new LinkButton();
link.CommandName = "LinkCommand";
link.Command += new CommandEventHandler(link_Command);
link.Text = "Yes";
link.ID = index.ToString();
label.Controls.Add(link);
}
else
{
PlaceHolder label = (PlaceHolder)e.Row.FindControl("HasPrevious");
Label noNote = new Label();
noNote.Text = "No";
label.Controls.Add(noNote);
}
Here is the gridview:
<asp:GridView runat="server" ID="LedgerGrid" AutoGenerateColumns="false"
onselectedindexchanged="LedgerGrid_SelectedIndexChanged"
onrowdatabound="LedgerGrid_RowDataBound" onrowcommand="LedgerGrid_RowCommand"
>
<Columns>
<asp:TemplateField HeaderText="Notes">
<ItemTemplate>
<asp:PlaceHolder ID="HasPrevious" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Invoice Date" DataField="invoicedate" DataFormatString="{0:d}" />
<asp:BoundField HeaderText="Invoice" DataField="invoice" />
<asp:BoundField HeaderText="Fee Debt" DataField="Fee_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Cost Debt" DataField="Cost_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="VAT Debt" DataField="VAT_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Total Debt" DataField="Total_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Client Code" DataField="ClientCode" />
<asp:ButtonField HeaderText="Matter Number" DataTextField="matternumber" CommandName="ViewMatter" />
<asp:BoundField HeaderText="Decription" DataField="matterdescription" />
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="AddInvoiceCheck" runat="server" Enabled="true" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
To make sure that my link button command works I am rebuilding the gridview as I would in the Page_load. Here is the page load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string clientCode = Server.HtmlEncode(Request.QueryString["clientcode"]);
items = DataAccess.DataAccess.GetLedgerDetails(clientCode);
ViewState["LedgerItems"] = items;
ViewState["clientcode"] = clientCode;
LedgerGrid.DataSource = items;
LedgerGrid.DataBind();
LedgerClientObject clientDetails = DataAccess.DataAccess.GetClientDetails(clientCode);
ClientCodeLabel.Text = string.Format("Group Code: {0}", clientDetails.GroupCode);
ClientNameLabel.Text = string.Format("Client Name: {0}", clientDetails.ClientName);
ClientCodeFilter.DataSource = clientDetails.ClientCodes;
ClientCodeFilter.DataBind();
}
}
To maintain the dynamically added controls on post back I am calling the following:
protected void Page_PreLoad(object sender, EventArgs e)
{
if (IsPostBack)
{
items = (List<LedgerItem>)ViewState["LedgerItems"];
LedgerGrid.DataSource = items;
LedgerGrid.DataBind();
}
}
Of course it now seems that by using this method I am overwriting the state of the check-box gridview column. Am I approaching this all wrong? I would like to be able to use the viewstate to maintain the set up of my dynamically added controls to the gridview. Is there a way I can access the state of the checkbox control form gridview before/after I reload the gridview in PreLoad event?
I am checking the state of my checkbox column with a button click as follows:
protected void Unnamed1_Click(object sender, EventArgs e)
{
NoteModel note = new NoteModel();
for (int i = 0; i < LedgerGrid.Rows.Count; i++)
{
int invoice = Convert.ToInt32(LedgerGrid.Rows[i].Cells[2].Text);
CheckBox check = (CheckBox)LedgerGrid.Rows[i].FindControl("AddInvoiceCheck");
if (check.Checked)
{
note.invoices.Add(invoice);
}
}
if (note.invoices == null)
{
string clientcode = (string)ViewState["clientcode"];
ViewState["InvoiceError"] = 1;
Response.Redirect(string.Format("Ledger.aspx?clientcode={0}", clientcode));
}
else
{
string clientcode = (string)ViewState["clientcode"];
Session["NoteObject"] = note;
Response.Redirect(string.Format("AddNote.aspx?cc={0}", clientcode));
}
}
Whenever I iterate over the checkbox controls in the gridview they are all unchecked e.g overwritten by my PreLoad code!!!
In the end I decided not to use dynamically created controls. Instead I added a buttonfield to the grid view. In my rowdatabound event I then set the visibility of the button to false if it does meet my criteria. This way view state is maintained as i do not need to create control on post back.
Seems with webforms that avoiding dynamic controls where possible is the best bet. I would still like to know which event to tap into to override viewstate re-instating controls?