Add row to inner repeater of nested repeaters at runtime c# - c#

I am building a web application to construct a document. The document has paragraphs (outer repeater) and subparagraphs (inner repeater). What I'm looking for is a way to add a blank subparagraph to an existing document.
My markup:
<asp:Repeater ID="ParagraphRepeater" runat="server"
OnItemDataBound="ParagraphRepeater_ItemDataBound" >
<ItemTemplate>
<asp:TextBox ID="ParagraphTitleTextBox" runat="server" Font-Bold="true" Width="300px"
Text='<%# Eval("ParagraphTitle") %>'></asp:TextBox>
<br />
<asp:TextBox ID="ParagraphTextTextBox" runat="server" TextMode="MultiLine" Wrap="true"
width="1100px" Height="50px" Text='<%# Eval("ParagraphText") %>'></asp:TextBox>
<asp:Button ID="DeleteParagraphButton" runat="server" Text="Delete" OnClick="DeleteParagraphButton_Click" />
<asp:Repeater ID="SubParagraphRepeater" runat="server" DataSourceID="SubParagraphSqlDataSource">
<ItemTemplate>
<div style="margin-left: 30px">
<asp:TextBox ID="SubParagraphTitleTextBox" runat="server" Font-Underline="true" Width="200px"
Text='<%# Eval("SubParagraphTitle") %>'></asp:TextBox>
<br />
<asp:TextBox ID="SubParagraphTextTextBox" runat="server" TextMode="MultiLine" Wrap="true"
Width="1050px" Height="50px" Text='<%# Eval("SubParagraphText") %>'></asp:TextBox>
<asp:Button ID="DeleteSubParagraphButton" runat="server" Text="Delete"
OnClick="DeleteSubParagraphButton_Click" />
<br />
</div>
</ItemTemplate>
</asp:Repeater>
<br />
<br />
<br />
</ItemTemplate>
My code:
protected void MultiView1_ActiveViewChanged(object sender, EventArgs e)
{
if (MultiView1.GetActiveView() == InputView)
{
BuildParagraphDataTable();
BuildSubParagraphDataTable();
if (RevisionsDropDownList.SelectedValue == "0")
{
// User is creating a new document
// Call method to create a datatable for the form row
SetFormRow();
// Call method to create a datatable for the paragraph row
AddParagraph();
DataTable dt = (DataTable)ViewState["ParagraphTable"];
ParagraphRepeater.DataSource = dt;
ParagraphRepeater.DataBind();
}
else
{
// User is opening an existing document
// Get the formId and save it to ViewState
int formId = Convert.ToInt32(RevisionsDropDownList.SelectedValue);
ViewState["FormId"] = formId.ToString();
// Bind the Paragraph repeater to its sqlDataSource
ParagraphRepeater.DataSource = ParagraphSqlDataSource;
ParagraphRepeater.DataBind();
}
}
}
protected void AddParagraph()
{
int paragraphId;
DataTable dt = (DataTable)ViewState["ParagraphTable"];
DataRow dr = dt.NewRow();
if (ViewState["ParagraphId"] != null)
paragraphId = Convert.ToInt32(ViewState["ParagraphId"]);
else
paragraphId = 0;
paragraphId--;
int formId = Convert.ToInt32(ViewState["FormId"]);
dr["ParagraphId"] = paragraphId;
dr["FormId"] = formId;
dr["ParagraphTitle"] = string.Empty;
dr["ParagraphText"] = string.Empty;
dr["CreatorId"] = string.Empty;
dr["RevisorId"] = string.Empty;
dt.Rows.Add(dr);
ViewState["ParagraphTable"] = dt;
ViewState["ParagraphId"] = paragraphId;
}
protected void AddSubParagraph()
{
DataTable dt = (DataTable)ViewState["SubParagraphTable"];
DataRow dr = dt.NewRow();
int paragraphId = Convert.ToInt32(ViewState["ParagraphId"]);
dr["ParagraphId"] = paragraphId;
dr["SubParagraphTitle"] = string.Empty;
dr["SubParagraphText"] = string.Empty;
dr["CreatorId"] = string.Empty;
dr["RevisorId"] = string.Empty;
dt.Rows.Add(dr);
ViewState["SubParagraphTable"] = dt;
}
protected void ParagraphRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
AddParagraph();
DataTable parentDataTable = (DataTable)ViewState["ParagraphTable"];
DataRow lastDTRow = parentDataTable.Rows[parentDataTable.Rows.Count - 1];
int paragraphId = (int)ViewState["ParagraphId"];
DataRowView thisParagraphRowView = (DataRowView)e.Item.DataItem;
paragraphId = (int)thisParagraphRowView.Row["ParagraphId"];
lastDTRow["ParagraphId"] = thisParagraphRowView.Row["ParagraphId"];
lastDTRow["FormId"] = thisParagraphRowView.Row["FormId"];
lastDTRow["ParagraphTitle"] = thisParagraphRowView.Row["ParagraphTitle"];
lastDTRow["ParagraphText"] = thisParagraphRowView.Row["ParagraphText"];
ViewState["ParagraphTable"] = parentDataTable;
ViewState["ParagraphId"] = paragraphId.ToString();
DataTable childDataTable;
DataRowView thisSubParagraphRowView;
Repeater childRepeater = (Repeater)e.Item.FindControl("SubParagraphRepeater");
foreach (RepeaterItem item in childRepeater.Items)
{
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
thisSubParagraphRowView = (DataRowView)item.DataItem;
if (thisSubParagraphRowView != null)
{
AddSubParagraph();
childDataTable = (DataTable)ViewState["SubParagraphTable"];
lastDTRow = childDataTable.Rows[childDataTable.Rows.Count - 1];
lastDTRow["ParagraphId"] = thisSubParagraphRowView.Row["ParagraphId"];
lastDTRow["SubParagraphTitle"] = thisSubParagraphRowView.Row["SubParagraphTitle"];
lastDTRow["SubParagraphText"] = thisSubParagraphRowView.Row["SubParagraphText"];
ViewState["SubParagraphTable"] = childDataTable;
}
}
}
}
}
When the user opens an existing form, the itemDataBound code populates the datatables for the paragraphs and subparagraphs. (These datatables will be used in the update to the database.)
When the user creates a new form, the setForm() and addParagraph() methods are called to create the form ID and add a blank paragraph. No blank subparagraph is added - the user must click a button to do so.
As for the data model, there is one Form (the user selects it from a ddl). A Form can have 1 to many paragraphs, and paragraphs can have zero to many subparagraphs.
I need to create a blank row in the inner repeater for a particular row in the outer repeater (the paragraph that the cursor is currently located in, or if the cursor is located in a subparagraph, the parent paragraph). How do I do that? I've done a ton of digging on Google but cannot find an entry that addresses this issue. Thanks.

The answer is to move the "AddSubParagraph" button from a standalone position to be inside the outer repeater. That way, the repeater can be located by using the "NamingContainer" attribute of the button. Then it's a matter of finding the inner repeater Repeater innerRepeater = (Repeater)outerRepeater.FindControl("childRepeater");, and adding a row to it. I can add the row but I'm having trouble DataBinding the inner repeater.
What I do is keep datatables in viewstate for each repeater, and mirror the data between the repeaters and the datatables. When I need to add a row, I add it to the datatable and then databind the repeater to the datatable. But I get an error: The line it errors on is childRepeater.Datasource = dt;. The error is "DataSource and DataSourceId are both defined. Remove one definition." DataSourceId is defined on the childRepeater in the markup, pointing to a SQLDataSource. So I need to find a way to bind the inner repeater to its SQLDataSource at retrieval time, on the fly.
One snag: I'm thinking I'd use the ItemDataBound event to do the databinding. But I already have a lot of code there (see above). Is there another event I can use that makes sense?

Related

2 DropDownLists on each row of Gridview

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">&nbsp
</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.

Asp.net C#: Cannot get inner content of fileuploads because the contents are not literal

I'm developing a web application using asp.net c#. I'm trying to create fileuploads dynamically. using the following code:
FileUpload[] fileuploadsarr = new FileUpload[uploads_table.Rows.Count];
int c = 0;
foreach (DataRow row in uploads_table.Rows)
{
Label att_name = new Label();
att_name.Text = row["TYPE"].ToString();
FileUpload fileupload = new FileUpload();
fileupload.CssClass = "form-control";
fileupload.ID = "fileupload"+ row["ID"].ToString();
fileupload.Attributes.Add("runat", "server");
fileuploads.Controls.Add(att_name);
fileuploads.Controls.Add(fileupload);
fileuploadsarr[c] = fileupload;
c = c + 1;
}
Session["myfileuploadsarr"] = fileuploadsarr;
when i try to reference the postedfile for each fileupload i got the null pointer exception. When i have debugged the code I've found this exception inside the parent attribute of the file upload
Parent = {InnerText = {System.Web.HttpException (0x80004005): Cannot get inner content of fileuploads because the contents are not literal.
Note: I'm adding the fileuploads on a div
<div id="fileuploads" runat="server">
</div>
i reference filesupload through:
FileUpload[] temp = (FileUpload[])Session["myfileuploadsarr"];
foreach (FileUpload row in temp)
{
OracleCommand cmd_docs = new OracleCommand();
System.IO.Stream fs = row.PostedFile.InputStream;
System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
...
}
I think you better could use a ListView. It saves you the trouble of generating dynamic controls. Note the use of DataKeyNames
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("TYPE") %>'></asp:Label>
<asp:FileUpload ID="FileUpload1" runat="server" CssClass="form-control" />
<br />
</ItemTemplate>
</asp:ListView>
<asp:Button ID="Button1" runat="server" Text="Upload files" OnClick="Button1_Click" />
And then in code behind you bind data to the ListView and process the uploaded files on a button click.
protected void Button1_Click(object sender, EventArgs e)
{
//loop all items in the listview
for (int i = 0; i < ListView1.Items.Count; i++)
{
//get the id from the datakeys if needed
int ID = Convert.ToInt32(ListView1.DataKeys[i].Values[0]);
//use findcontrol to locate the fileupload and cast it back
FileUpload fu = ListView1.Items[i].FindControl("FileUpload1") as FileUpload;
//check if it exists and has a file
if (fu != null && fu.HasFile)
{
//save the file
}
}
}
The binding of the DataTable uploads_table to the ListView to make this demo complete.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
//bind the datatable to the listview
ListView1.DataSource = uploads_table;
ListView1.DataBind();
}
}

Improving Grouping Speed in Gridview

I have a web form where I need to group items/rows based on some criteria. It has multilevel grouping and that is why rendering items in the gird becomes very tedious process for the server.
Here is what I do currently. (This is for only 3 level).
protected void ResultGrid_PreRender(object sender, EventArgs e)
{
foreach (GridViewRow gdR in ResultGrid.Rows)
{
Label lblClass = (Label)gdR.FindControl("lblClass");
Label lblCategory = (Label)gdR.FindControl("lblCategory");
Label lblCompartment = (Label)gdR.FindControl("lblCompartment");
Panel pnlClassLinks = (Panel)gdR.FindControl("pnlClassLinks");
foreach (GridViewRow gdRIn in ResultGrid.Rows)
{
if (gdRIn.RowIndex != gdR.RowIndex)
{
Label lblClassIn = (Label)gdRIn.FindControl("lblClass");
Label lblCategoryIn = (Label)gdRIn.FindControl("lblCategory");
Label lblCompartmentIn = (Label)gdRIn.FindControl("lblCompartment");
if(lblClassIn.Text == lblClass.Text)
{
if(lblCategoryIn.Text == lblCategory.Text)
{
if(lblCompartmentIn.Text == lblCompartment.Text)
{
LinkButton lnkBtn = new LinkButton();
// lnkBtn Properties added
pnlClassLinks.Controls.Add(lnkBtn);
if (pnlClassLinks.Controls.Count > 2)
{
pnlClassLinks.Width = 150;
}
if (gdR.Visible)
{
dr.Visible = false;
}
}
}
}
}
}
LinkButton lnkGroupEdit = (LinkButton)gdR.FindControl("lnkGroupEdit");
lnkGroupEdit.OnClientClick = "editGroup();";
}
}
As it clearly shows, the rows iteration is too much, when the number of rows in gridview increases. So, is there any better way to do this?
You can create a GenericCollection. Include your customised properties like (width, cssClass, visibility...). Then bind this collection to the gridView as a dataSource.
gridView.DataSource= List_CustomModel;
gridView.DataBind();
this is a scope from a code i manipulate
`
<asp:TemplateField>
<HeaderTemplate>
<asp:Literal ID="LtBodac" runat="server" Text="BODACC" />
</HeaderTemplate>
<HeaderStyle CssClass="css-bodacc" />
<ItemTemplate>
<asp:TextBox Visible='<%#Eval("Bodacc") %>' ID="TbDateBodac" CssClass="datebox source-manuel css-bodacc CustomDateMercure" runat="server" Text='<%#Eval("DateBodac")%>' /><asp:HiddenField Visible='<%#Eval("Bodacc") %>' ID="HfOldDateBodac" runat="server" Value='<%#Eval("DateBodac")%>' /> </ItemTemplate>
</asp:TemplateField>
NB:#Eval("Bodacc") :Boddac is a property in my model.

Strategy - Gridview to Excel export full records

I know there are a bunch of questions with detailed instructions on exporting from gridview to excel, but I can't find my particular situation.
I have a gridview that displays records with five fields from a search. Users can check in a checkbox any number of records. On a button click, I can successfully export only the checked records to Excel. Export is as HTML. I'm using the technique from Matt Berseth here: http://mattberseth.com/blog/2007/04/export_gridview_to_excel_1.html
I added a check for whether the record was checked by the user and this works fine.
But I have a requirement that for the checked records that are exported, the users want to see the entire records (i.e. all fields in just the selected records).
What is a good strategy to accomplish this?
I've tried retrieving all fields in the gridview and setting all but the five desired fields to not visible. Then in the export button click event, setting the fields to visible and rebinding. No luck there.
Thanks for any help.
Sounds like you should loop through the rows to see which are checked.
foreach (GridViewRow row in gridView.Rows)
{
if(row.RowType == DataControlRowType.DataRow)
{
CheckBox cb = row.FindControl("CheckBoxID") as CheckBox;
if(cb != null && cb.Checked)
{
// Logic here.
}
}
From there, you can export to excel using several different mechanisms, depends on your needs. One I've used in the past if you just need xls files is NPOI -- it's open source and provides a decent framework for it. Here is a link to their site:
http://npoi.codeplex.com/
-- EDIT
After reading your comments, maybe this will help.
ASPX Code:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Checkbox Column">
<ItemTemplate>
<asp:CheckBox ID="CheckBoxID" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Visible Column">
<ItemTemplate>
<asp:Label ID="lblVisibleColumn" runat="server" Text='<%# Eval("VisibleColumn")%>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hidden Column" Visible="false">
<ItemTemplate>
<asp:Label ID="lblHiddenColumn" runat="server" Text='<%# Eval("HiddenColumn")%>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="btnExport" runat="server" Text="Export" OnClick="btnExport_Click" />
Backend Code:
public class MyDataColumn
{
public string visibleColumn { get; set; }
public string hiddenColumn { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable dataTable = new DataTable();
List<MyDataColumn> dataColumns = new List<MyDataColumn>();
for (int i = 0; i < 10; i++)
{
dataColumns.Add(new MyDataColumn()
{
visibleColumn = string.Format("Visible Column {0}", i),
hiddenColumn = string.Format("Hidden Column {0}", i)
});
}
gridView.DataSource = dataColumns;
gridView.DataBind();
}
}
protected void btnExport_Click(object sender, EventArgs e)
{
List<MyDataColumn> dataColumnsToExport = new List<MyDataColumn>();
foreach (GridViewRow row in gridView.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
CheckBox cb = row.FindControl("CheckBoxID") as CheckBox;
if (cb != null && cb.Checked)
{
Label lblVisibleColumn = row.FindControl("lblVisibleColumn") as Label;
Label lblHiddenColumn = row.FindControl("lblHiddenColumn") as Label;
dataColumnsToExport.Add(new MyDataColumn()
{
visibleColumn = lblVisibleColumn.Text,
hiddenColumn = lblHiddenColumn.Text
});
}
}
}
GridView gridViewToExport = new GridView();
gridViewToExport.DataSource = dataColumnsToExport;
gridViewToExport.DataBind();
//Do Something With gridViewToExport
//GridViewExportUtil.Export("GridView.xls", gridViewToExport);
}
And this should be easy to convert to a DataTable if needed -- I used my own class to make it shorter code.

Update ASP Label inside ASP Datalist

I have an ASP Datalist with a nested GridView.
I am trying to display an ASP label for each list item where the gridview has more than 6 rows and keep it hidden for those list items where the gridview has < 6 rows.
Here is the datalist:
<asp:DataList runat="server" id="listResponses" DataKeyField="QuestionID" OnItemDataBound="listResponses_ItemDataBound" Width="100%">
<ItemTemplate>
<div class="question_header">
<p><strong><asp:Label ID="lblOrder" runat="server" Text='<%# Container.ItemIndex + 1 %>'></asp:Label>. <%# DataBinder.Eval(Container.DataItem, "QuestionText") %></strong></p>
</div> <!-- end question_header -->
<asp:GridView runat="server" ID="gridResponses" DataKeyNames="AnswerID" AutoGenerateColumns="False" CssClass="responses" AlternatingRowStyle-BackColor="#f3f4f8">
<Columns>
<asp:BoundField DataField="AnswerTitle" HeaderText="Answer Title" HeaderStyle-ForeColor="#717171" ItemStyle-Width="250px"></asp:BoundField>
<asp:BoundField DataField="Responses" HeaderText="Response Count" HeaderStyle-ForeColor="#717171" HeaderStyle-Width="100px" />
<asp:TemplateField>
<ItemTemplate>
<div class="pbcontainer">
<div class="progressbar"></div>
<asp:HiddenField ID="hiddenValue" runat="server" Value='<%# Eval("Responses") %>' />
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<a><asp:Label runat="server" ID="lblShowResponses" Visible="false"></asp:Label></a>
</ItemTemplate>
</asp:DataList>
The label I am trying to update is lblShowResponses.
The method to populate the datalist:
// populate datalist.
DT = GetData.GetQuestionNameDataList(qid);
listResponses.DataSource = DT;
listResponses.DataBind();
And the gridview is populated as follows:
protected void listResponses_ItemDataBound(object sender, DataListItemEventArgs e)
{
GridView gridResponses = (GridView)e.Item.FindControl("gridResponses");
BindGrid(gridResponses, (int)listResponses.DataKeys[e.Item.ItemIndex], DT.Rows[e.Item.ItemIndex][2].ToString());
}
// Get the question ID from the datalist and parse the parameters to BindGrid
protected void listResponses_ItemDataBound(object sender, DataListItemEventArgs e)
{
GridView gridResponses = (GridView)e.Item.FindControl("gridResponses");
BindGrid(gridResponses, (int)listResponses.DataKeys[e.Item.ItemIndex], DT.Rows[e.Item.ItemIndex][2].ToString());
}
private void BindGrid(GridView GridView, int questionId, string questionType)
{
// get the answerID and title for the current question.
DataTable answersDataTable = new DataTable();
answersDataTable = GetData.GetAnswerResponses(questionId);
DataTable tempResponses = new DataTable();
// checkbox question type - loop through each answer and obtain the number of responses.
for (int answer = 0; answer < answersDataTable.Rows.Count; answer++)
{
// populate tempaory datatable and replace DT with the response count.
string answerID = answersDataTable.Rows[answer][0].ToString();
tempResponses = GetData.getIndividualQuestionResponses(questionId, answerID);
answersDataTable.Rows[answer][2] = tempResponses.Rows[0][0];
}
if (GridView.Rows.Count > 6)
{
for (int x = 6; x < GridView.Rows.Count; x++)
{
GridView.Rows[x].Visible = false;
}
// I want to populate the label here!!!!!!
}
}
How can I update/populate the label lblShowResponses when the gridview contains more than 6 rows?
Not sure if this would help you, pass the DataListItemEventArgs param "e" to the BindGrid method and in the location you want to populate the label and use
(e.Item.FindControl("lblShowResponses") as Label).Text = "Test";
(e.Item.FindControl("lblShowResponses") as Label).Visible = true;

Categories

Resources