Create Unique Buttons Inside Repeater - c#

I have a list of items that are retrieved and can have varying amounts. Because of this, I have a Repeater to create a dynamic amount of rows to display each item in. I need a button in each row that can change some of the properties of the item in the list for that specific row. I'm only able to create the same button for each row in the aspx file which means I have no way to determine which row to change because all of the buttons are the same. See below:
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<li class="list-group-item"><%# Container.DataItem %>
<asp:Button ID="btn" runat="server" />
</li>
</ItemTemplate>
</asp:Repeater>
The list items are displayed with a loop, so i've removed the button from the aspx page and instead tried to create buttons in this loop but they are not displaying.
for (int i = 0; i < listItems.Length; i++)
{
openList.Add("ID: " + item[i]);
repeater.DataSource = openList;
Button btn = new Button();
btn.ID = i.ToString();
repeater.Controls.Add(btn);
repeater.DataBind();
}

Don't worry. The buttons are not the same. The framework will ensure that they are unique. And if you want to know which button was clicked, you can send a CommandArgument to the OnCommand method.
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<li class="list-group-item"><%# Container.ItemIndex %>
<asp:Button ID="btn" runat="server" CommandArgument='<%# Container.ItemIndex %>' OnCommand="btn_Command" />
</li>
</ItemTemplate>
</asp:Repeater>
Code behind
protected void btn_Command(object sender, CommandEventArgs e)
{
//if you need to access the button itself
Button btn = sender as Button;
//get the correct index from the commandargument
Label1.Text = e.CommandArgument.ToString();
}

Related

OnClick Event for panel which is inside a repeater

<asp:Panel id="contactsListContainer" runat="server">
<asp:Repeater ID="contactsListRepeater" runat="server">
<ItemTemplate>
<asp:Panel CssClass="contactsList" ID="contactList" runat="server" OnClick="contactLink_Click" CommandArgument='<%# ((AddressBook.Employee)Container.DataItem).Id %>' CausesValidation="false">
<asp:Label ID="lblContactName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>'></asp:Label>
<asp:Label ID="lblContactEmail" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Email") %>'></asp:Label>
<asp:Label ID="lblContactMobile" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "MobileNumber") %>'></asp:Label>
</asp:Panel>
</ItemTemplate>
</asp:Repeater>
</asp:Panel>
I want to add onclick event for contactlist panel. how can i add it.
This is the code what is to be done when that panel is clicked.
protected void contactLink_Click(object sender, EventArgs e)
{
contactsForm.Style.Add("display", "none");
detailsContainer.Style.Add("display", "block");
LinkButton btn = (LinkButton)sender;
SelectEmpId = int.Parse(btn.CommandArgument);
LinkButton contactListLinkButton = getSelctedLinkButton();
contactListLinkButton.Style.Add("background-color", "#CEE7F2");
Employee employee = GetEmployee(SelectEmpId);
lblDetailName.Text = employee.Name;
lblDetailAddress.Text = employee.Address;
lblDetailMobile.Text = employee.MobileNumber;
lblDetailLandline.Text = employee.LandLineNumber;
lblDetailEmail.Text = employee.Email;
lblDetailWebsite.Text = employee.Website;
lblDetailAddress.Text = employee.Address;
}
There is no OnClick event for Asp.NET Panel, try this instead:
You can refer to this solution: https://stackoverflow.com/a/20540854/4779385
Hope it helps!
The <asp:Panel> does not have a Click event you can handle.
Although you will probably have some CSS work to do, a good approach is to wrap the content you want to be server-clickable inside an HTML anchor, i.e.
<a id="anchor" runat="server">
.. your stuff
</a>
You can add a Clicked handler to the anchor inside the repeater/grid's ItemDataBound event, and specify your contactLink_Click handler is the one to handle the event for all anchors/panels in the repeater/grid.
(this example is from a repeater, adapt it for a GridView)
void contactsListRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var item = e.Item;
if (item.ItemType == ListItemType.AlternatingItem || item.ItemType == ListItemType.Item)
{
var anchor = item.FindControl("anchor") as HtmlAnchor;
anchor.ServerClick += contactLink_Click;
}
}
Note that the sender will be the anchor that raises the click event, so you can drill down into the correct child controls from sender (if you need to)

C# Repeater dynamic Button

I am using repeater to generate the button control.
<asp:Repeater ID="rptDoc" runat="server">
<ItemTemplate>
<div style="...">
<asp:Button ID="btnUpload" runat="server" Text="Button" OnClick="button_Click" />
</div>
</ItemTemplate>
</asp:Repeater>
For example, I can generate 4 buttons. However, how can I implement
the program inside each of the button?
when btnUpload1 clicked, it will upload files into Folder1,
when btnUpload2 clicked, it will upload files into Folder2
I know there is a way that create a Table in the web form, and then
dynamically put the generated button inside the table cells... But I
have lots of DIVs with styling, so I don't want to use a table to
place the dynamic buttons.
Thanks for help.
It works for me now, I used the LinkButton instead of Button.
Also added OnItemCommand="ItemCommand" in repeater.
And finally it will goto ItemCommand event when LinkButton clicked.
It gets the value from CommandArgument which set in dynamic LinkButton
<asp:Repeater ID="rpt" runat="server" OnItemCommand="ItemCommand">
<ItemTemplate>
<asp:LinkButton runat="server" CommandArgument='<%# Eval("lbtnUploadCommandArgument")%>' CommandName="ButtonEvent">Upload Files</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
protected void ItemCommand(Object Sender, RepeaterCommandEventArgs e)
{
string[] arr_Para = ((LinkButton)e.CommandSource).CommandArgument.Split(';');
}
When you dynamically add buttons to the web form, you can track what each button should be doing and then process that URL in a common click event, like the hackish example below.
Dictionary<System.Web.UI.WebControls.Button, string> ButtonToURIMap = new Dictionary<System.Web.UI.WebControls.Button, string>();
private void AddButtonToForm()
{
System.Web.UI.WebControls.Button myWebButton = new System.Web.UI.WebControls.Button();
//Initialize/Style your button here.
myWebButton.Click +=myWebButton_Click;
ButtonToURIMap.Add(myWebButton, "http://www.google.com/");
}
void myWebButton_Click(object sender, EventArgs e)
{
if (sender is System.Web.UI.WebControls.Button)
{
System.Web.UI.WebControls.Button callingButton = (System.Web.UI.WebControls.Button)sender;
if ( ButtonToURIMap.ContainsKey(callingButton))
{
string uri = ButtonToURIMap[callingButton];
//code you execute from here
}
}
}
All you need is below.
in your codebehind
Protected Sub MyPointsRepeater_RowCommand(sender As Object, e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles MyPointRepeater.ItemCommand
arg = e.CommandArgument.ToString().Split(";"c)
End Sub
in your Aspx page
<asp:Repeater ID="MyPointRepeater" runat="server">
<ItemTemplate>
<label class="ConferenceName"><%#Eval("Conference Name").ToString()%></label><br />
<label class="RegistrationId"><%#Eval("CPD Points / Hours").Tostring() %></label>
<label class="Type"><%#Eval("Type").ToString()%></label>
<asp:LinkButton ID="lnkCustomize" Text="Download Certificate" CommandName="Customize" CssClass="fontLight"
CommandArgument='<%#Eval("R_Id").Tostring() + ";" + Eval("Conf_Id").Tostring() + ";" + Eval("Reg Id").Tostring() + ";" + Eval("CPD Points / Hours").Tostring() + ";" + Eval("Type").Tostring()%>' runat="server" />
</ItemTemplate>
</asp:Repeater>

Firing different linkbuttons in a Repeater and saving the value of each in an arraylist

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.

ASP.NET Button OnClick within Repeater and LoginView

I'm developing a ASP.NET website with a C# backend. I'm having a problem with how to set an onclick event for buttons that are nested inside of both a loginview and a repeater. The code works fine for displaying all of the other data (anonymous view displays only an error message) but right now the buttons just redirect to the same page and remove the repeater and all contents, whereas they're supposed to run a specific delete function. The repeater, as it is right now, uses an alternatingitem template. If I remove the buttons from the nested controls, they work. I've tried this with buttons, linkbuttons, and imagebuttons. I'd rather use the latter, if possible. Is it possible to assign an Onclick to these buttons if they're nested like this? If not, what approach should I use?
<asp:LoginView ID="LoginLinksView" runat="server" EnableViewState="false">
<AnonymousTemplate>
<asp:Label ID="errorlabel" runat="server"></asp:Label>
</AnonymousTemplate>
<LoggedInTemplate>
<asp:Repeater id="Repeater" runat="server" >
<HeaderTemplate>
<table cellspacing="0" cellpadding="0">
<thead></thead>
</HeaderTemplate>
<ItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</AlternatingItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</LoggedInTemplate>
</asp:LoginView>
Here are the problems with your approach
1- The button issues postback as it should. But you need to put some CommandArgument with to identify "key" or which row you are processing it for.
2- Re Bind your Repeater with source. Below is the sample code for you.
protected void Page_Load(object sender, EventArgs e)
{
BindRepeater();
}
private void BindRepeater()
{
List<int> items = new List<int>();
for (int i = 0; i < 10; i++)
{
items.Add(i);
}
Repeater.DataSource = items;
Repeater.DataBind();
}
protected void DeleteOnClick(object sender, EventArgs e)
{
ImageButton delbutton = (sender as ImageButton);
//1- call your method with passing in delbutton.CommandArgument - it will give you key/ whatever you like
//2- Rebind the Repeater here and that will bind controls again...
BindRepeater();
}
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
ImageButton delbutton = (sender as RepeaterItem).FindControl("delbutton") as ImageButton;
if (delbutton != null)
{
delbutton.CommandArgument = (sender as RepeaterItem).ItemIndex.ToString();
}
}
and ASPX Repeater definition would change to
Thanks,
Riz

Limit the number of results in a Nested ASP.NET ListView

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);

Categories