Retrieving and updating server control values in a ListView - asp.net

In the past I've used jQuery Ajax to create a shopping cart. This time around I'm using the list view server control.
If I have a qty text box in each row and I want to update the quantity on a button click is this the most elegant way to achieve this?
protected void Button1_Click(object sender, EventArgs e)
{
foreach(ListViewItem item in ListViewCart.Items)
{
foreach (Control con in item.Controls)
{
if (con.GetType() == typeof(TextBox))
{
//Do Work.
}
}
}
}
I'm guessing that I would need to store the productID in a custom attribute for each textbox and use it when updating the database. (Or write more code to find that value somewhere else in the row.)
More importantly, is there a different server control I might want to use instead? I don't want to use the gridview.

I guess you could shorten it a little bit like this
foreach (TextBox txtBox in
ListViewCart.Items.SelectMany(item => item.Controls.OfType<TextBox>()))
{
//do work like - txtBox.Text = "foo";
}

Related

Dynamically create buttons with onclick function

I want to dynamically create buttons for each cell in a table, which works fine. The problem is that i now want to assign them server side click events, like this:
Button b = new Button();
b.Text = "Delete";
b.CssClass = "btnDelete";
b.Click += new EventHandler(this.deletePictures_Click);
While this would be my deletePictures_Click:
private void deletePictures_Click(object sender, EventArgs e)
{
test.Text = "hi";
}
But it won't fire. I did quite some research but couldn't find anything that helped me, yet. Do you guys know what's wrong?
Thanks in advance!
Edit:
Here's the rendered HTML
<td class="resultCell">
<img class="resultpicture" src="photos/DSC_101.jpg">
<input name="ctl00$cphContentBox$ctl02" value="Delete" class="btnDelete" type="submit"></td>
Edit:
I saved all the buttons in a List and then in the Session. In the OnInit I iterated the List, assigning the Button.OnClientClick to each of them. But the event still won't fire! Here's the code:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Session["buttons"] != null)
{
buttons = (List<Button>)Session["buttons"];
for (int i = 0; i < buttons.Count; i++)
{
buttons[i].OnClientClick += new EventHandler(deletePictures_Click);
}
}
}
The easy idea is to use a grid-view instead a table.
In the above problem you need to recreate you element on pre_init evetn.
Here is a good link
http://social.msdn.microsoft.com/Forums/en-US/dbc12b8c-8796-4800-a45f-57f24b8ef72b/dynamically-created-button-event-is-not-working
you need to create an array of objects (i think a collection of them), then cycle them with a foreach construct
at school i did it in java, printing buttons in a table with foreach and collections

asp.net treeview programmatically setting node color

I want to set the node colors of a treeview at runtime. I populate the treeview from a collection that has the parentid, childid, and description, and I've added a property representing the color I want applied to the node. FWIW the source is a database, the app is C#.
In a gridview I use RowDataBound() to programmatically affect the control. Im not sure how to do so in the treeview, including which event to use (DataBound()? TreeViewDataBound()?). My research has not been fruitful so far. A code snippet would be very useful.
Hopefully this will give you a raging clue.
When setting a node text, instead of setting
Node Text
set as
<div style='color: red'>Node Text</a>
you can use Prerender event:
protected void TreeView1_PreRender(object sender, EventArgs e)
{
if (IsPostBack) return;
foreach (TreeNode t in TreeView1.Nodes)
{
if (t.Value.EndsWith("1")) //Some Condition
{
string s = t.Text;
string fs = "<span style=\"color: #CC0000\">" + s + "</span>";
t.Text = fs;
}
}
}
Since .NET Framework 4.5 you can use these style properties:
TreeView.LevelStyles Property - represent the node styles at the
individual levels of the tree
TreeView.RootNodeStyle Property
TreeView.ParentNodeStyle Property
TreeView.LeafNodeStyle
Property
Assuming you are dealing with the standard TreeView control, you can do this in the TreeDataBound Event.
A brief example (not tested):
<asp:TreeView runat="server"
ID="tvMyTreeView"
OnTreeNodeDataBound="tvMyTreeView_TreeNodeDataBound"
/>
And the backend:
protected void tvMyTreeView_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
DataRowView dr = (DataRowView)e.Node.DataItem;
e.Node.Style.Add("color", dr["COLOR"].ToString());
}
If you are using the Telerik RadTreeView, then the event name is NodeDataBound
You will probably have to tweak the example to better fit your needs, but hopefully this will get you started.

format for url to point to radio button selection [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
linking to a radio button selection, asp.net c#
i have a page with a textarea and radio buttons. the text area is populated with data based on the radio button selection. i want the radio button selection to appear in the url so that a user can link to the radio button selection.
i'm hoping that all i need to do i modify my querystring to include radio button value. here's the data caputered by fidler when i make a radio button selection.
__EVENTTARGET ctl00$MainContent$RadioButtonList1$6
__EVENTARGUMENT
__LASTFOCUS
__VIEWSTATE /+++PC9wPg0KPHA+/....
__EVENTVALIDATION /wEWCwKY7d6oAQLh8vmTCALk7M7lDQK+6NunDwK/6OenDwK86OenDwK86OunDwK86POnDwK96NenDwK96NunDwKxh73KA3Q+PMuKU/JUCKsF1aiY2DNLu7/pFFni/Qtz+7FXy35g
ctl00$MainContent$RadioButtonList1 41
i'm hoping my url simply needs to look something like this to point to the radio button value but and all i need is the appropriate syntax:
http://www.test.com/test.aspx?ctl00$MainContent$RadioButtonList1$41
---code behind ---
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack == false)
{
RadioButtonList1.SelectedIndex = 0;
RadioButtonList1.DataBind();
}
else
{
string strRedirect;
strRedirect = "frm_Articles.aspx?Article_PK=" + RadioButtonList1.SelectedValue.ToString();
Response.Redirect(strRedirect);
}
}
protected void SqlDataSource2_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
//
}
protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
try{
e.Command.Parameters["#URL_FK"].Value = Session["URL_PK"];
}
catch (Exception ex)
{
}
}
}
One thing to note is that you have misconstructed your url. It should be:
http://www.test.com/test.aspx?ctl00$MainContent$RadioButtonList1=41
(note the third to last character is an =.
Apart from that it would depend on how your page works in terms of picking up the selected radio button. My advice would be to just try it and see what happens. However, I would suspect that if you are doing it based on an event firing on page load (ie some kind of postback behaviour) then it won't work.
If this is the case then you will just want to do something on page load to check if that value exists in the url and set it before you load up the text. If you end up going down this route you might want to consider using a more well defined and user friendly querystring parameter. In particular the id you have there is built based on its position in the control hierarchy. If you were to redesign your HTML structure the ID might well change.
Additionally...
With the code you've provided where you set the selectedindex of your radiobutton list you need to find out what value you need before you set it and set it to 0 if you have no better value (though it looks like you are setting to 0 before binding whcih seems superfluous). Something like this may work (not compiled or tested so apologies for typos - it is designed to give you the general idea more than to be finalised code).
if (Page.IsPostBack == false)
{
RadioButtonList1.DataBind();
//Check if you have a value to set.
if (Request.Querystring(RadioButtonList1.ClientID)!=null)
{
//Get the value
string setValue = Request.Querystring(RadioButtonList1.ClientID)
//Find the right radio option to select
foreach(ListItem item in RadioButtonList1.Items)
{
if (item.Value == setValue)
{
item.Selected = true;
break;
}
}
}
}
I assume it will default to the selected index being 0 if nothing is set as selected otherwise.
Anyway, this code is meant as a starting point to work from. There may be other ways to do it and some may even be better.

Set focus on textbox after postback

I have a search page with 3 TextBoxes that users can filter a search with.
I have put the focus on the TextBox that contains text. If more than one contains text just focus on last TextBox.
private void SetFocusOnTextBox(ControlCollection ctrlCollection)
{
foreach (Control ctrl in ctrlCollection)
{
if (ctrl.GetType() == typeof(TextBox))
{
if (((TextBox)ctrl).Text != string.Empty)
{
SetFocus(ctrl);
}
}
}
}
After the code runs and a user searches, the focus comes to the beginning of the TextBox, not the end where it would be presumed. How to put insert marked at the end of that TextBox?
I think the answer is here: Use JavaScript to place cursor at end of text in text input element.
Taken from the linked solution: You have to add onfocus="this.value = this.value" to the three controls in the markup file. This is not so easy in ASP.NET as it should be, but one solution is to add the attribute in the code behind file.
protected void Page_Init(object sender, EventArgs e)
{
// MoveCursorToEndOnFocus is called in Page_Init and not Page_Load to avoid
// filling the ViewState with unnecessary data.
// TODO: Call MoveCursorToEndOnFocus here.
}
private void MoveCursorToEndOnFocus(ControlCollection controlCollection)
{
foreach (TextBox textBox in controlCollection
.Where(control => control.GetType() == typeof(TextBox)))
{
textBox.Attributes.Add("onchange", "this.value = this.value");
}
}
Shouldn't it be
if (((TextBox)ctrl).Text == string.Empty)
to advance to the bottommost empty textbox? If it is if (((TextBox)ctrl).Text != string.Empty), it will set focus (eventually) to the bottommost nonempty textbox.
As for advancing your cursor to the last character, try this:
function cursorToEnd( elem )
{
elem.focus();
elem.value+='x';
elem.value=elem.value.replace(/x$/,"");
}

How to programmatically create and use a list of checkboxes from ASP.NET?

I have a page with a table of stuff and I need to allow the user to select rows to process. I've figured out how to add a column of check boxes to the table but I can't seem to figure out how to test if they are checked when the form is submitted. If they were static elements, I'd be able to just check do this.theCheckBox but they are programaticly generated.
Also I'm not very happy with how I'm attaching my data to them (by stuffing it in there ID property).
I'm not sure if it's relevant but I'm looking at a bit of a catch-22 as I need to known which of the checkboxes that were created last time around were checked before I can re-run the code that created them.
Edit:
I've found an almost solution. By setting the AutoPostBack property and the CheckedChanged event:
checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);
I can get code to be called on a post back for any check box that has changed. However this has two problems:
The call back is processed after (or during, I'm not sure) Page_Load where I need to use this information
The call back is not called for check boxes that were checked when the page loaded and still are.
Edit 2:
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
I'm going to assume you're using a DataList but this should work with and Control that can be templated. I'm also going to assume you're using DataBinding.
Code Front:
<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
<ItemTemplate>
<asp:CheckBox ID="DeleteMe" runat="server"/>
<a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
<%# DataBinder.Eval(Container, "DataItem.Title")%></a>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
Code Behind:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadList();
}
protected void DeleteListItem_Click(object sender, EventArgs e)
{
foreach (DataListItem li in List.Items)
{
CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
if (delMe != null && delMe.Checked)
//Do Something
}
}
LoadList();
}
protected void LoadList()
{
DataTable dt = //Something...
List.DataSource = dt;
List.DataBind();
}
protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
if (delMe != null)
delMe.Attributes.Add("value", id);
}
}
}
First, make sure that each Checkbox has an ID and that it's got the 'runat="server"' in the tag.
then use the FindControl() function to find it.
For example, if you're looping through all rows in a GridView..
foreach(GridViewRow r in Gridview1.Rows)
{
object cb = r.FindControl("MyCheckBoxId");
if(r != null)
{
CheckBox chk = (CheckBox)cb;
bool IsChecked = chk.Checked;
}
}
Postback data is restored between the InitComplete event and the PreLoad event. If your checkboxes are not created until later then the checkboxes will play "catch up" with their events and the data will be loaded into the control shortly after it is created.
If this is to late for you then you will have to do something like what you are already doing. That is you will have to access the post data before it is given to the control.
If you can save the UniqueId of each CheckBox that you create then can directly access the post data without having to given them a special prefix. You could do this by creating a list of strings which you save the ids in as you generate them and then saving them in the view state. Of course that requires the view state to be enabled and takes up more space in the viewstate.
foreach (string uniqueId in UniqueIds)
{
bool data = Convert.ToBoolean(Request.Form[uniqueId]);
//...
}
Your post is a little vague. It would help to see how you're adding controls to the table. Is it an ASP:Table or a regular HTML table (presumably with a runat="server" attribute since you've successfully added items to it)?
If you intend to let the user make a bunch of selections, then hit a "Submit" button, whereupon you'll process each row based on which row is checked, then you should not be handling the CheckChanged event. Otherwise, as you've noticed, you'll be causing a postback each time and it won't process any of the other checkboxes. So when you create the CheckBox do not set the eventhandler so it doesn't cause a postback.
In your submit button's eventhandler you would loop through each table row, cell, then determine whether the cell's children control contained a checkbox.
I would suggest not using a table. From what you're describing perhaps a GridView or DataList is a better option.
EDIT: here's a simple example to demonstrate. You should be able to get this working in a new project to test out.
Markup
<form id="form1" runat="server">
<div>
<table id="tbl" runat="server"></table>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</div>
</form>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
var row = new HtmlTableRow();
var cell = new HtmlTableCell();
cell.InnerText = "Row: " + i.ToString();
row.Cells.Add(cell);
cell = new HtmlTableCell();
CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
cell.Controls.Add(chk);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is CheckBox)
{
// do your processing here
CheckBox chk = c as CheckBox;
if (chk.Checked)
{
Response.Write(chk.ID + " was checked <br />");
}
}
}
}
}
}
What about using the CheckBoxList control? I have no Visual Studio open now, but as far as I remember it is a DataBound control, providing DataSource and DataBind() where you can provide a list at runtime. When the page does a postback you can traverse the list by calling something like myCheckBoxList.Items and check whether the current item is selected by calling ListItem.Selected method. This should work.
Add them in an override of the CreateChildControls method of the Page. Be sure to give them an ID! This way they get added to the control tree at the correct time.
IMHO The best way would be to use DataBound Templated Control though, i.e. something like a ListView (in .NET 3.5). then in pageload after postback traverse all items in the databound control and use item.FindControl to get at the actual checkbox.
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.

Resources