How to get an item from asp:Repeater in Event handler? - c#

I have a Repeater that is binded with some DataTable. (Here I skiped header template).
<asp:Repeater ID="rpt_users" runat="server" OnItemCommand="rpt_users_ItemCommand" OnItemDataBound="rpt_users_ItemDataBound">
<ItemTemplate>
<tr class="c0">
<td><asp:CheckBox ID="CheckSelect" runat="server" /></td>
<td>
<asp:HyperLink ID="hpl_edit" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "name") %>'
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "edit") %>'></asp:HyperLink></strong>
<asp:LinkButton ID="btn_del" runat="server" CommandName="Remove" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "key") %>'><img src="assets/img/delete.png" alt="<%#nodeDelete %>" title="<%#nodeDelete %>" class="ico-delpage icon-right" /></asp:LinkButton>
</td>
<td>
<p><%# DataBinder.Eval(Container.DataItem, "country") %></p>
</td>
<td>
<asp:TextBox runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "daysleft") %>' OnTextChanged="Unnamed_TextChanged" AutoPostBack="true"/>
</td>
</tr>
</ItemTemplate>
<asp:Repeater>
I associated OnTextChanged event with a handler:
protected void Unnamed_TextChanged(object sender, EventArgs e)
{
var txt = (sender as TextBox).Text;
int newDays = 0;
try
{
newDays = int.Parse(txt);
}
catch { return; }
}
So, how to get the whole object that is associated with current row in Repeater? I need to get access to this object in my OnTextChanged event handler, because I need to get some data from this object that represents current row.

You cannot access the bound object of the repeater item in the OnTextChanged event. One way of doing this is as follows.
After retrieving the datatable, save the datatable in viewstate
ViewState["Data"] = data;
Bind the key value of the individual item to a hidden field by adding a hidden field to the repeater item
< asp:HiddenField runat="server" ID="hiddenFieldKey" Value='<%# DataBinder.Eval (Container.DataItem, "key") %>' />
You can get the, repeater item and then the hidden field, to get the key of the row. Then the other values can be retrieved by finding the rows in the table which is stored in the viewstate.
protected void Unnamed_TextChanged(object sender, EventArgs e)
{
var txt = (sender as TextBox).Text;
var repeaterItem = (sender as TextBox).NamingContainer as RepeaterItem;
var hiddenFieldKey =repeaterItem.FindControl("hiddenFieldKey") as HiddenField;
// Get data from viewstate
DataTable data = ViewState["Data"] as DataTable;
var dataRow= data.Rows.Find(hiddenFieldKey.Value);
//You can use this row to get the values of the other columns
int newDays = 0;
try
{
newDays = int.Parse(txt);
}
catch { return; }
}
Another way of doing is that, if you dont have many values to get, then bind all the required values in multiple hidden fields in the repeater item and then get those hidden field values in the OnTextChanged event

You can use the sender parameter, like you do for Text, var tb = (TextBox)sender;, then access that control's Parent property. You might have to go a couple levels up to find exactly what you're looking for, but that's the gist. Then you can use FindControl or whatever you need past that.

Related

Accessing SelectedItem from DDL within Repeater's ItemCommand

Hey all — I'm trying to access the SelectedItem value from a DropDown list that is housed within a Repeater, but I am receiving a Null Exception that is thrown. This repeater would iterate over upwards of 10 "products". Here is the code from my Web Form:
<asp:repeater ID="rptProducts" runat="server" OnItemDataBound="rptProducts_ItemDataBound" OnItemCommand="rptProducts_ItemCommand">
<ItemTemplate>
<div class="col-md-8 col-md-offset-2 product">
<img src="<%# Eval("ImageFile") %>" class="col-xs-12" alt="<%# Eval("Name") %> Product Image"/>
<h3><%# Eval("Name") %></h3>
<p><%# Eval("ShortDescription") %></p>
<asp:DropDownList ID="DropDownList1" runat="server"></asp:DropDownList>
<asp:Button ID="Button1" runat="server" Text="Add to Cart" CommandName="click" CommandArgument='<%# Eval("Name") %>' UseSubmitBehavior="false" />
</div>
</ItemTemplate>
</asp:repeater>
And the code from the .cs file where I'm trying to access DropDownList1's SelectedItem value.
protected void rptProducts_ItemCommand(object sender, CommandEventArgs e)
{
Repeater rpt = (Repeater)sender;
DropDownList productDDL = (DropDownList)rpt.Items[0].FindControl("DropDownList1");
int Qty = Convert.ToInt32(productDDL.SelectedItem.Text);
Debug.WriteLine(rpt.ID);
if (e.CommandName == "click")
{
Debug.WriteLine("Clicked " + e.CommandArgument.ToString() + "; Quantity: " + Qty);
}
}
The Exception is being thrown at this line:
int Qty = Convert.ToInt32(productDDL.SelectedItem.Text);
I'm trying to prep that data to be pushed into a Session state, so I'm testing to ensure it is accessible. Is there something I'm missing and or a better way to access that specific value?
In rptProducts_ItemCommand event you are using fixed item index 0, you need to select the item that fired item command
Below line of code will select the current triggered item.
DropDownList productDDL = (DropDownList)((RepeaterCommandEventArgs)e).Item.FindControl("DropDownList1");

Bind SC Images in Sitecore

I'm having a repeater control and want to bind Images to the sc control for onitemdatabound event.
My markup is:
<sc:Link runat="server" ID="sclnk" Field="#" rel="iframe-960-540">
<sc:image id="scimage" runat="Server" field="#">
</sc:image>
</sc:Link>
And my code is:
Sitecore.Web.UI.WebControls.Link scBannerLink = e.Item.FindControl("sclnk") as Sitecore.Web.UI.WebControls.Link;
if (scBannerLink != null)
{
scBannerLink.DataBind(promoItem.ID.ToString(), promoItem.PromoLink.Field.InnerField.Name);
}
Sitecore.Web.UI.WebControls.Image scPromoImage = e.Item.FindControl("scimage") as Sitecore.Web.UI.WebControls.Image;
if (scPromoImage != null)
{
scPromoImage.DataBind(promoItem.ID.ToString(), promoItem.PromoImage.Field.InnerField.Name);
}
I'm not getting any error but not diaplaying images
I've never used the Databind method of the control to set the properties.
The easier solution is to specify the Fieldname and set the Item in your repeater:
<asp:Repeater runat="server" ID="rptImages">
<ItemTemplate>
<sc:Link runat="server" ID="scLnk" Field="MyLinkFieldName" Item="<%# Container.DataItem %>" Parameters="rel=iframe-960-540">
<sc:image id="scImage" runat="Server" Field="MyImageFieldName" Item="<%# Container.DataItem %>" />
</sc:Link>
</ItemTemplate>
</asp:Repeater>
And you can pass in the additional attributes in the Parameters field on the control as a URL encoded parameters string, e.g. Parameters="rel=iframe-960-540&param2=value2&param3=value3"
And your code behind binding the control should be:
protected void Page_Load(object sender, EventArgs e)
{
rptImages.DataSource = Sitecore.Context.Item.GetChildren(); // this needs to be changed to whatever your query is...
rptImages.DataBind();
}

Label ASP not being set

I have a label that is dynamically generated via a repeater, rollNo is a label that's a part of the itemTemplate. When I check the value of l, it goes in the if block but l.Text is still empty. check.Text only returns "d". Why?
Label l = (Label)item.FindControl("rollNo");
TextBox t = (TextBox)item.FindControl("quiz1");
if (l != null)
{
string a = l.Text;
check.Text = "d"+a;
}
Your code sample isn't complete as it has no rollNo in it, but I can tell you something...
You are using repeater and with that using template...The id you use inside the template is never will be the run-time id of any of your controls! Think about it! Let say you assigned rollNo to one of the elements in the template and you have 10 rows to pass to the repeater. Are you expecting to have 10 controls with the the same id of rollNo?! I hope not!
For that reason FindControl will return nothing while using on id inside a template...
You have to rethink what do you want or use a different approach to find the controls (loop)...
Repeater Markup:
<asp:Repeater id="Repeater1" runat="server" OnItemCommand="Repeater1_ItemCommand">
<ItemTemplate>
<tr onclick="rowReturn(this)">
<td><asp:Label CssClass="form-control" runat="server" ID="rollNo"><%# DataBinder.Eval(Container.DataItem, "sid") %></asp:Label></td>
<td><asp:TextBox CssClass="form-control" runat="server" ID="quiz1" required></asp:TextBox></td>
<td><asp:TextBox CssClass="form-control" runat="server" ID="quiz2" required></asp:TextBox></td>
<td><asp:Button CssClass="btn btn-success btn-sm form-control" ID="add" CommandName="add" runat="server" Text="Add" CommandArgument='<%#DataBinder.Eval(Container.DataItem, "sid") %>' /></td>
</tr>
</ItemTemplate>
Code Behind:
TextBox t1;
TextBox t2;
string rollNumber, T1, T2;
if (e.CommandName == "add")
{
// get CommandArgument you have selected on the button
string roll = e.CommandArgument.ToString();
rollNumber = roll;
foreach (RepeaterItem item in Repeater1.Items)
{
t1 = (TextBox)item.FindControl("quiz1");
t2 = (TextBox)item.FindControl("quiz2");
T1 = t1.Text;
T2 = t2.Text;
//...DB code or any other code
}
}

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.

How to pass in runtime a index of row for ListView?

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.

Categories