I have already done a lot of research about this here in stackoverflow and in the msdn documentation, however, nothing has helped. I need to be able to select an item in my asp: listview and take that text that I select and put it into a string to be used later. Here's the code of my .aspx:
<li class="menu-item menu-item-has-children">
Undécimo
<ul runat="server" id="eleventhList" class="sub-menu">
<asp:ListView ID="listViewforEleventh" runat="server" OnItemCommand="listViewforEleventh_ItemCommand">
<ItemTemplate>
<a onserverclick="linkForEleven_ServerClick" runat="server" id="linkForEleven" href="ViewSchedule.aspx"> <asp:Label ID="eleventhGroupLabel" runat="server" Text="<%#Container.DataItem %>"></asp:Label> </a>
<asp:Label runat="server" ID="dataString"></asp:Label>
</ItemTemplate>
</asp:ListView>
</ul>
</li>
I'm populating the list view like this:
private void loadEleventh()
{
list = group.getGroupsByLevelService(11);
List<string> sublist = new List<string>();
foreach (var element in list)
sublist.Add(element.GroupName);
listViewforEleventh.DataSource = sublist;
listViewforEleventh.DataBind();
}
This works, but now I need to select the data (text) that is in the sp:ListView. I am doing it like this:
protected void linkForEleven_ServerClick(object sender, EventArgs e)
{
ListViewDataItem item = listViewforEleventh.Items[listViewforEleventh.SelectedIndex];
Label c = (Label)item.FindControl("dataString");
groupName = c.Text;
}
When I debugged my code I got an error of index out of range exception in the selectedIndex method with the value -1. How can I solve this? Or how can I take the data from the listview item and store it in a string in another way?
In your SelectedIndexChanged event handler, do this:
string valueToSave = YourListBox.SelectedValue.ToString();
Of course, you have to make sure that you have actually selected an item in the ListBox in order for there to be a value for YourListbox.SelectedValue. This is just an example of how to do this once. I don't know the details behind how you want to use this value, of course.
Related
Im using a repeater to display some products in an online shop for a school project. This is how the front end looks with the repeater
<asp:Repeater ID="Repeater1" runat="server" OnItemCommand="rptList_ItemCommand">
<ItemTemplate>
<span style="float:left; padding:25px;" class="backgrnd">
<asp:ImageButton ID="imgProd" runat="server" style="width:150px; height:150px;" ImageUrl='<%# DataBinder.Eval(Container.DataItem, "productImg")%>' CommandArgument='<%# DataBinder.Eval(Container.DataItem, "productID")%>' CommandName="ViewIndividProd"/><br />
<p style="clear:left;">
<asp:Label ID="lbName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "productName")%>' /><br />
<asp:Label ID="lbUnitPrice" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "unitPrice")%>'/><br />
<asp:Label ID="lbRatings" runat="server" Text=''>Ratings</asp:Label><br />
<asp:LinkButton ID="linkCart" runat="server" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "productID")%>' CommandName="AddToCart">Add to Cart</asp:LinkButton>
</p>
</span>
</ItemTemplate>
</asp:Repeater>
As you can see I've added on the OnItemCommand in the Repeater tag so that this is invoked whenever one of the buttons(image/link) is fired. That works perfectly fine for both commandname AddToCart and ViewIndividProd. However, i want to store the the productid of a specific item that was invoked by the particular button. In my case now, it only stores ONE productid in the arraylist at a time and 'forgets' the productid that was stored previously when another linkbutton is clicked.
Question How do i make it such that everytime a linkbutton in the repeater is fired, it remembers the productid pertaining to the linkbutton that was fired and save these ids into the arraylist?
This is how the back end looks
ArrayList cart = new ArrayList();
protected void rptList_ItemCommand(object sender, RepeaterCommandEventArgs e) {
if (e.CommandName == "ViewIndividProd") {
Session["productID"] = e.CommandArgument.ToString();
Response.Redirect("IndividProduct.aspx");
}
if (e.CommandName == "AddToCart") {
string prodid = e.CommandArgument.ToString();
cart.Add(prodid);
Session["ShoppingCart"] = cart;
Response.Redirect("IndividCat.aspx");
}
msg.Text = "Shopping cart: " + String.Join(",", cart.ToArray());
}
Your feedback would be much appreciated.
You need to understand the Asp.net Page life cycle.
A new instance of your Page object is created on every request.
Values from your input are populated into it.
Your array list is getting recreated every time.
If you want the values to persist, you will have to store your arraylist in the ViewState or the Session
Refer: How to: Save Values in View State
void Page_Load(object sender, EventArgs e)
{
if (ViewState["arrayListInViewState"] != null)
{
PageArrayList = (ArrayList)ViewState["arrayListInViewState"];
}
else
{
// ArrayList isn't in view state, so we need to create it from scratch.
PageArrayList = CreateArray();
}
// Code that uses PageArrayList.
}
We can store comma separated or JSON value in either Session or hidden variable (If you are on the same page and opening new page in different tab then we can use hidden variable also). So every time an button has been click we can append the product id.
Sort of new to .NET and trying to understand how best to accomplish this task: I have a listview with a datasource containing a list of string values. The last property is some text that I'd like to place in the Text template; normally when not used inside a listview I can place markup and text inside the template successfully, so I'd like to keep this structure. But what would be a way of placing that string inside there? I've tried Databinder.Eval but as expected it says that the template doesn't contain the property I'm referring to from Container.DataItem (which becomes the template).
<asp:ListView runat="server"
ID="ListView1"
OnItemDataBound="ListView1_ItemDataBound">
<LayoutTemplate>
<div class="navigation">
<asp:PlaceHolder runat="server" id="itemPlaceholder" />
</div>
</LayoutTemplate>
<ItemTemplate>
<my:Control id="VideoLink1" runat="server">
<Text>
--- PLACE CONTENT HERE --
</Text>
</my:Control>
</ItemTemplate>
</asp:ListView>
Anyone have an idea how to accomplish this? Would be greatly appreciated.
Use ItemDatabound event of the ListView. In that find your control and then assign the desired properties.
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
YourControl VideoLink1= e.Item.FindControl("VideoLink1") as YourControl ;
if(VideoLink1!= null)
{
YourClass obj = ((YourClass)(((System.Web.UI.WebControls.ListViewDataItem)(e.Item)).DataItem));
VideoLink1.TextProperty = obj .TextProperty ;
}
}
}
I need to know how to nest repeaters within a user control. The html side of things is fine, it's the binding and code behind I need help with. I've only been able to find examples using an sql data source, which doesn't really help.
My repeaters look like this:
<asp:Panel ID="pnlDiscipline" runat="server" CssClass="">
<asp:Repeater ID="rptDiscipline" runat="server">
<ItemTemplate>
<h4><%#Eval("Discipline")%></h4>
<ul>
<asp:Repeater ID="rptPrograms" runat="server">
<ItemTemplate>
<li><asp:HyperLink runat="server" Text='<%#Eval("Name") %>' NavigateUrl='<%#Eval("Link") %>'></asp:HyperLink> <%#Eval ("Notation") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
What I need to do is hopefully reasonably clear - the h4 discipline should appear once, all the entries that belong to the discipline are listed below, then the next h4, then the appropriate list, the next h4 and so on.
The datasource is a dataview created in the codebehind where each row has 'Name', "Link', 'NOtation' and 'Discipline'. I've bound the dataview to the outermost repeater, and it behaves as expected - lists the discipline name for each entry, but shows no data in the inner repeater.
How do I go about making this work?
EDIT: Just to clarify, I have one datatable in the codebehind. Each row in that table is an item, each item belongs to a discipline. I want to use the outer repeater to list the disciplines, the inner to list the items grouped under each discipline. Like so:
<h4>DISCIPLINE 1</h4>
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
<h4>DISCIPLINE 2</h4>
<ul>
<li>Item</li>
<li>Item</li>
</ul>
<h4>DISCIPLINE 3</h4>
<ul>
<li>Item</li>
<li>Item</li>
</ul>
At present, binding the datatable to the outer repeater gives this (example uses the data above):
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 2</h4>
<h4>DISCIPLINE 2</h4>
<h4>DISCIPLINE 3</h4>
<h4>DISCIPLINE 3</h4>
I've used OnItemDataBound on the outer repeater as suggested, and as a test case am able to access the data:
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
DataRowView drView = (DataRowView) e.Item.DataItem;
string name = drView["Name"] as string;
string link = drView["Link"] as string;
string notation = drView["Notation"] as string;
Response.Write(name + link + notation + "<br />")
}
So the data is there, it is exactly what I would expect to see, I just can't get it bound to the inner repeater. If there is a more performant way to achieve the same, I'm happy to rework my solution.
On the outer control, use the ItemDataBound event, like this:
<asp:Repeater ID="rptDiscipline" runat="server"
OnItemDataBound="rptDiscipline_ItemDataBound">
...
Then, in the code-behind, handle the rptDiscipline_ItemDataBound event and manually bind the inner repeater. The repeater's ItemDataBound event fires once for each item that is repeated. So you'll do something like this:
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
// To get your data item, cast e.Item.DataItem to
// whatever you're using for the data object; for example a DataRow.
// Get the inner repeater:
Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");
// Set the inner repeater's datasource to whatever it needs to be.
rptPrograms.DataSource = ...
rptPrograms.DataMember = ...
rptPrograms.DataBind();
}
EDIT: Updated to match your question's update.
You need to bind the outer repeater to a data source that has only one record per item you want the repeater to render. That means the data source needs to be a collection/list/datatable/etc that has only the disciplines in it. In your case, I would recommend getting a List<string> of disciplines from the DataTable for the inner collection, and bind the outer repeater to that. Then, the inner repeater binds to a subset of the data in the DataTable, using the ItemDataBound event. To get the subset, filter the DataTable through a DataView.
Here's code:
protected void Page_Load(object sender, EventItems e)
{
// get your data table
DataTable table = ...
if ( !IsPostBack )
{
// get a distinct list of disciplines
List<string> disciplines = new List<string>();
foreach ( DataRow row in table )
{
string discipline = (string) row["Discipline"];
if ( !disciplines.Contains( discipline ) )
disciplines.Add( discipline );
}
disciplines.Sort();
// Bind the outer repeater
rptDiscipline.DataSource = disciplines;
rptDiscipline.DataBind();
}
}
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
// To get your data item, cast e.Item.DataItem to
// whatever you're using for the data object
string discipline = (string) e.Item.DataItem;
// Get the inner repeater:
Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");
// Create a filtered view of the data that shows only
// the disciplines needed for this row
// table is the datatable that was originally bound to the outer repeater
DataView dv = new DataView( table );
dv.RowFilter = String.Format("Discipline = '{0}'", discipline);
// Set the inner repeater's datasource to whatever it needs to be.
rptPrograms.DataSource = dv;
rptPrograms.DataBind();
}
If you don't want to do it on the ItemDataBound event, you can also do it inline in your page by binding to a child property of the parent item if the child property is a collection like so:
<asp:Repeater runat="server" ID="OuterRepeater" >
<ItemTemplate>
Outer Content: <%# DataBinder.Eval(Container.DataItem, "ParentProperty")%>
<asp:Repeater runat="server" ID="InnerRepeater" DataSource='<%# DataBinder.Eval(Container.DataItem, "ChildCollection")%>' >
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "ChildProperty")%>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
First you need two lists, the list of disciplines, and then the list of all your data.
Data bind the list of disciplines to the outer repeater. If there are 6 disciplines, the repeater should repeat 6 times.
<asp:Repeater ID="rptDiscipline" runat="server" OnItemDataBound="rptDiscipline_ItemDataBound">
<ItemTemplate>
<h4><%# Eval("Discipline")%></h4>
<ul>
<asp:Repeater runat="server" ID="InnerRepeater" >
<ItemTemplate>
<li>
<asp:Label runat="server" ID="lbl" />
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
Repeater inner= (Repeater) e.Item.FindControl("InnerRepeater");
//You want to bind all the data related to this discipline
DataRowView drView = (DataRowView) e.Item.DataItem;
string discipline= drView["Discipline"] as string;
//filter your total data with ones that match the discipline
inner.DataSource = //data bind the filtered list here
inner.DataBind();
}
Similar to my other question:
I have a ListView bound to a Dictionary. Then I have a nested ListView for the dictionary's value's integers.
I need to limit the number of items bound to the nested list to something like 5, and show a more button in the template.
I can't find a way to get the more button to work, and to correctly limit the number at the same time. I have it working as one or the other right now.
Any ideas? Thanks!
UPDATE:
The markup looks something like this:
<asp:ListView runat="server" ID="MainListView" ItemPlaceholderID="PlaceHolder2">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="PlaceHolder2" />
</LayoutTemplate>
<ItemTemplate>
<h1>My Main ListView - <%# Eval("Key") %></h1>
<asp:ListView runat="server" ID="NestedListView" ItemPlaceholderID="PlaceHolder3"
DataSource='<%# Eval("Value") %>' >
<LayoutTemplate>
<h2>One of many Nested ListViews</h2>
<asp:PlaceHolder runat="server" ID="PlaceHolder3" />
</LayoutTemplate>
<ItemTemplate>
<asp:LinkButton runat="server" ID="AnInteger" Text='<%# Eval("value") %>'></asp:LinkButton>
<br />
</ItemTemplate>
</asp:ListView>
<asp:LinkButton runat="server" ID="uxMoreIntegers" Text="More..." Visible="false" OnClick="uxMoreIntegers_Click"></asp:LinkButton>
</ItemTemplate>
</asp:ListView>
DataBind the main ListView anyway you want.
DataBind the nested ListView programmatically in the ItemDataBound event for the main ListView
Code:
protected void uxListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem item = (ListViewDataItem)e.Item;
// Get the bound object (KeyValuePair from the dictionary)
KeyValuePair<string, List<int>> nestedIntegerList = (KeyValuePair<string, List<int>>)item.DataItem;
// Get our nested ListView for this Item
ListView nestedListView = (ListView)e.Item.FindControl("uxNestedListView");
// Check the number of items
if (nestedIntegerList.Value.Count > 5)
{
// There are more items than we want to show, so show the "More..." button
LinkButton button = (LinkButton)item.FindControl("uxMore");
button.Visible = true;
}
// Bind the nestedListView to wahtever you want
nestedListView.DataSource = nestedIntegerList.Value.Take(5);
nestedListView.DataBind();
}
}
The Take method will return the first 5 items in your list, but won't modify the list itself. You can then simply check the number of items in the list to determine if the more button needs to be enabled.
someList.Take(5); //use these items in your ListView
moreButton.Enabled = (someList.Count > 5);
I have an question, On my page i have a ListView control, I also have a button that has CommandArgument. I know i can read and find a control in the ListView as :
ListView.Items[i].FindControl("controlname");
and my button in ListView is like that
asp:Button ID="WisdomButton" runat="server" CommandName="UpdateWisdom" CommandArgument='<%# need my index for Item[i] to post here %>'
OnCommand="UpdateWisdom" Text="Update" />
I want to add index value in runtime to the CommantParameter, so when i go to the Function onCommand i will know exactly from what row[i] i Need to get my controls from ListView.
So my question is, how do i dinamicly add index of ListView.Rows[i] into CommmandArgument for the Button in runtime ?
Thanks in advance.
Check out the API
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listviewcommandeventargs.aspx
The ListViewCommandEventArgs item has an index, IE it is already available in the argument
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
int i = dataItem.DisplayIndex;
But from here you will have access to those controls
e.Item.FindConrol("controlName");
If you are calling the method a different way you could aways assign the index through an ItemDataBound Event
void MyListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
((Button)e.Item.FindControl("WisdomButton")).CommandArgument = ((ListViewDataItem)e.Item).DisplayIndex;
}
OR try something like this for giggles
<asp:Button runat="server" CommandArgument='<%# DisplayIndex %>'/>
// OR
<asp:Button runat="server" CommandArgument='<%# NextIndex() %>'/>
It might help to know a little bit more about what your are trying to do. If your end goal is to get any of the properties from your bound object you can just cast the dataItem from the ListViewCommandEventArgs of the ItemCommand event. You don't need to retain the index or call FindControl at all.
Here is an example of how to get the bound Customer object.
ListView
<asp:ListView runat="server" id="Customers" ItemCommand="Customers_ItemCommand">
<LayoutTemplate>
<ul>
<asp:placeholder runat="server" id="itemPlaceholder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<asp:Button runat="server" id="Select" CommandName="Select" />
<%# Eval("Name")%>
</li>
</ItemTemplate>
</asp:ListView>
CodeBehind
public void Page_Load()
{
if (!Page.IsPostBack)
{
this.Customers.DataSource = GetCustomers();
this.Customers.DataBind();
}
}
public void Customers_ItemCommand(object sender, ListViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
if (e.Item.ItemType != ListViewItemType.DataItem)
return;
var customer = ((ListViewDataItem)e.Item).DataItem as Customer;
if (customer != null)
{
// Now work directly with the customer object.
Response.Redirect("viewCustomer.aspx?id=" + customer.Id);
}
}
}
Edit: In addtion when you cast the item to a ListViewDataItem, then you also expose a ((ListViewDataItem)e.Item).DataItemIndex property that might help you.