I have an ASP:Repeater Which I would like to display a list of check boxes in. These check boxes are related to a list of user preferences and the users resulting answer. See Code Bellow.
I would like to add do one of the following if possible
Option 1: It would be great if I could use the Event in the Repeater:OnItemCommand(...) to fire if any of the items change. It would seem to me that this event will only fire if there is a Button | LinkButton | ImageButton item in the list. IE it will not fire if I put in a check box with AutopostBack="True"
Option 2: Is there a way I could attach a method to an Event of CheckBox:CheckChanged I would need to pass this method a parameter saying which question/answer combo to change.
Option 3: Its your answer if you know an easier way that would be awesome.
The Code:
<asp:Repeater ID="RPTprefs" runat="server" DataSourceID="getAnswers" OnItemCommand="RPTprefs_ItemCommand">
<ItemTemplate>
<li><asp:CheckBox ID='questionID' runat="server"
Checked='<%# Eval("pr.up_is_selected") %>'
Text='<%# Eval("prp.prefs_question") %>'
AutoPostBack="true"
OnCheckedChanged="CheckChanged" /></li>
</ItemTemplate>
</asp:Repeater>
Thanks in advance
Here is what I came up with, which is basically your option #2.
In the ItemTemplate of the repeater, I use a Literal control (Visible set to false) which has the argument you wish to pass to the CheckedChanged function. The reason for using a control is because the control will retain its value in the ViewState after a post back, whereas the original data source for the Repeater will be lost.
In the OnItemCreated function, I bind the CheckChanged function for all of the check boxes to pass in the right argument. Here's my complete example. In this case, I want to pass the Id property of my data to the CheckChanged function.
Markup:
<asp:Repeater ID="Repeater1" runat="server" OnItemCreated="ItemCreated">
<ItemTemplate>
<asp:Literal ID="litArg" runat="server" Visible="false" Text='<%# Eval("Id") %>'>
</asp:Literal><%# Eval("Name") %>
<asp:CheckBox ID="chkCool" runat="server" AutoPostBack="true" Checked='<%# Eval("IsCool") %>' /><br />
</ItemTemplate>
</asp:Repeater>
Code behind:
public class SomeClass
{
public SomeClass(bool c, string n, int id)
{
IsCool = c;
Name = n;
Id = id;
}
public bool IsCool { get; set; }
public string Name { get; set; }
public int Id { get; set; }
}
.
.
.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<SomeClass> people = new List<SomeClass>();
people.Add(new SomeClass(true, "Will", 666));
people.Add(new SomeClass(true, "Dan", 2));
people.Add(new SomeClass(true, "Lea", 4));
people.Add(new SomeClass(false, "Someone", 123));
Repeater1.DataSource = people;
Repeater1.DataBind();
}
}
private void CheckChanged(int id)
{
Response.Write("CheckChanged called for item #" + id.ToString());
}
protected void ItemCreated(object sender, RepeaterItemEventArgs e)
{
//this needs to be set again on post back
CheckBox chk = (CheckBox)e.Item.FindControl("chkCool");
Literal arg = (Literal)e.Item.FindControl("litArg");
Action<object, EventArgs> handler = (s, args) => CheckChanged(Convert.ToInt32(arg.Text));
chk.CheckedChanged += new EventHandler(handler);
}
Hope that helps.
Related
I want to dipslay in a Gridview with radiobutton list the current date when I run the project. I don't know if the best way is to use JavaScript or C# (I'm using it on Code Behind) and how to do it. If is need to show some code, say it. The grid is filled with a sql statement. The image below shows how I want the grid. Thank you
Unfortunately, you cannot use RadioButton.GroupName Property in GridView.
Easiest way is to place RadioButton in TemplateField, and use jQuery to manipulate it.
ASPX
<asp:GridView runat="server" ID="GridView1">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:RadioButton runat="server" ID="MyRadioButton"
CssClass="myRadioButton"
onclick='<%# "myRadioButtonClick(this)" %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
function myRadioButtonClick(sender) {
$('.myRadioButton input').attr('checked', false);
$(sender).attr('checked', true);
}
</script>
Code Behind
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = new List<Customer>
{
new Customer {Id = 1, Name = "John"},
new Customer {Id = 2, Name = "Marry"},
};
GridView1.DataBind();
}
In aspx page:
<asp:ListView ID="ListViewPosts" ItemType="Post"
SelectMethod="ListViewPosts_GetData" runat="server"
OnItemCommand="Insert_Comment"
OnItemDataBound="ListViewPosts_ItemDataBound">
...
...
</asp:ListView>
Code behind:
protected void Insert_Comment(object sender, ListViewCommandEventArgs e)
{
...
Post p = Item; //where Item stands for the current Post record in ListView.
...
}
If I have this ListView where in ItemType="Post"; Post is a database table.
How to access the current value of Item (which stands for the current record from thePost table) in the code behind method Insert_Comment
I asked a question for OnItemDataBound method and the code:
Post p = e.Item.DataItem as Post works well. I tried the same code for OnItemCommand but the variable Post p gets null value!!.
I can use CommandArgument but I am wondering if I can get the Post item directly like the way I can with OnItemDataBound methos.
You can use use .DataItem only within OnItemDataBound. You may pass the Id of the Item and use it to bring the Item back from the database:
<asp:ListView ID="ListViewPosts" ItemType="Post"
SelectMethod="ListViewPosts_GetData" runat="server"
OnItemDataBound="ListViewPosts_ItemDataBound">
<ItemTemplate>
<asp:LinkButton runat="server" ID="btn_InsertComment" CommandName="Insert_Comment" CommandArgument='<%# Eval("PostID") %>' Text="Insert" />
</ItemTemplate>
</asp:ListView>
protected void Insert_Comment(object sender, ListViewCommandEventArgs e)
{
LinkButton btn_InsertComment = (LinkButton) sender;
string postId = btn_InsertComment.CommandArgument;
//use this id to create a new comment
}
I'm having some trouble with a LoginView that is nested inside a Repeater in my ASP.NET 4.5 site. The data gets properly bound when the page loads. But if some external event rebinds the repeater, the content inside the LoginView templates doesn't rebind. I've simplified my code down about as much as I can to make it repeatable. Run this page, then click the Rebind Data button. The button labels disappear. How do I get those to properly rebind (ex: show the Text of the data item that it's bound to)? I would think that calling DataBind() on the repeater would rebind all child controls, but I guess not. I tried a couple different iterations of manually binding (and none worked), but would prefer a clean implementation.
RepeaterTest.aspx
<%# Import Namespace="MyNamespace" %>
<asp:Repeater runat="server" ID="MyRepeater">
<ItemTemplate>
<asp:LoginView runat="server">
<LoggedInTemplate>
<asp:Button runat="server" Text='<%# ((Container.Parent as RepeaterItem).DataItem as TestClass).Text %>' /><br />
</LoggedInTemplate>
<AnonymousTemplate>
<asp:Button runat="server" Text='<%# ((Container.Parent as RepeaterItem).DataItem as TestClass).Text %>' /><br />
</AnonymousTemplate>
</asp:LoginView>
</ItemTemplate>
</asp:Repeater>
<asp:Button runat="server" Text="Rebind Data" OnClick="Unnamed_Click" />
RepeaterTest.aspx.cs
namespace MyNamespace
{
public partial class RepeaterTest : System.Web.UI.Page
{
List<TestClass> list = new List<TestClass>()
{
new TestClass("hi"),
new TestClass("hello"),
new TestClass("bonjour"),
new TestClass("hola")
};
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MyRepeater.DataSource = list;
MyRepeater.DataBind();
}
}
protected void Unnamed_Click(object sender, EventArgs e)
{
MyRepeater.DataSource = list;
MyRepeater.DataBind();
}
}
public class TestClass
{
public string Text { get; set; }
public TestClass(string text)
{
Text = text;
}
}
}
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.
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.