Find and change a specific item in Repeater - c#

I have the following <asp:Repeater>:
<asp:Repeater ID="repMenuParent" runat="server" DataSourceID="odsMenuParent" OnItemCommand="repMenuParent_OnItemCommand" OnItemDataBound="repMenuParent_OnItemDataBound" >
<ItemTemplate>
<asp:Button id="btnRepeaterParent" runat="server" SkinID="btnAgroquimicos" CssClass="celdasMenusDinamicas" Text='<%# Eval("NOMBRE") %>' CommandName='<%# Eval("NOMBRE") %>' />
</ItemTemplate>
</asp:Repeater>
When the commandEvent is triggered i set up a session with the commandName and the uniqueId:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Session.Add("nombreSubMenuAgro", e.CommandName);
String id = e.Item.UniqueID;
Session.Add("souceId", id);
}
The issue is the following: I need change the forecolor of the botton inside the repeater that is cicked by the user. In the beginnig all the buttons (items in the repeater) are gray. When someone is clicked I need to change the forecolor of it to red (like a bread crumb).
I've trying to find the item in the itemDataBound and compare the uniqueId but it doesn't work, i don't know how to find the specific item that is clicked to change the forecolor:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
String sessionID = "";
Button btnRepeater;
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
btnRepeater = (Button)e.Item.FindControl("btnRepeaterParent");
if (btnRepeater != null)
{
if(btnRepeater.UniqueID.Equals(sessionID))
{
btnRepeater.ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
}
I've read many blog's threads about repeater and find it's items, but can´t find any that solved my issue, Can help me please?

I think this problem is best solved with Javascript though I do have a server side solution for you.
The command event object has a property called CommandSource. This gives you access to the button that triggered the command event.
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Button btnRepeater=e.CommandSource;
btnRepeater.ForeColor = Drawing.Color.Red;
}

If you maintain a List of the IDs of the buttons pressed, then you can do the following:
First, change your button in the repeater to use CommandArgument not CommandName. Like so:
<asp:Button id="btnRepeaterParent" ... CommandArgument='<%# Eval("NOMBRE") %>' />
Create a page level property for accessing the list of IDs. Like so:
public List<string> ClickedIds
{
get
{
if(Session("ClickedIds") == null)
Session("ClickedIds") = new List<string>();
return (List<string>)Session("ClickedIds");
}
}
When one of your buttons in your repeater is clicked, handle it like so:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
this.ClickedIds.Add(e.CommandArgument);
}
Now, when you are binding the repeater in code-behind, check each button like so:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
//retrieve the id of the data item
//I am not sure of your data item structure, but it will be something to this effect
int nombre = e.Item.DataItem("NOMBRE");
if(this.ClickedIds.Contains(nombre))
{
((Button)e.Item.FindControl("btnRepeaterParent")).ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
DISCLAIMER:
I have not tested this code.

Related

ASP.net listview with state

I have a dynamic list in ASP.net front end. User can click a button and add as many entries as it wants.
I'm using ViewState to save this data:
if(ViewState["items"] != null)
{
ListItems.DataSource = ViewState["items"];
}
ListItems.DataBind();
And there is a callback as follows:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
}
It's working fine, the problem is that, every time I add a new item, I loose any data I've entered in the other rows. How can I keep this information?
Edit:
I'm calling it from the .aspx page:
<asp:ListView ID="ListItems" class="block" SortExpression="DataType" ItemStyle-Wrap="false" runat="server">
<ItemTemplate >
<table>
<tr>
<asp:TextBox ID="Name" runat="server" class="inline" Text='<%# Eval("text") %>'></asp:TextBox>
</tr>
</table>
</ItemTemplate>
</asp:ListView>
Thanks in advance
Where are you calling this method? Are you calling in the same page? Before you construct the List you might be assigning to ListItems control.
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
ListItems.DataSource = ue;
ListItems.DataBind();
}
In this line, you can assign the collection to List and bind while adding in the ViewState.
There could be several points to check:
If you are assigning the values to ViewState on Page_Load then you might not be checking if it is a postback or not to overcome it you could just simply do the values assignment part to ListItems in an if condition: if(!Page.IsPostback){/* do stuff */ }
You might want to bind the ListItems each time you modify your list
You Could simply tweak with your code to see where the issue is nobody can help you investigate your code better than you!
Or finally, you may want to skip the ViewState at all, what you can do is:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue = (List<UserEntry>)ListItems.DataSource;
if(ue == null)
{
ue = new List<UserEntry>();
}
ue.Add(new UserEntry());
ListItems.DataSource = ue;
ListItems.DataBind();
} // Just an idea though

Adding Clickable Controls during a Click Event ASP.NET

I have an ASP.NET webform that has a Listbox that I'm adding items to dynamically using a Button (using Session to save the list between postbacks). When an Item is added to the Listbox I want to add an ImageButton that I can click to change the color of the newly created button. I know I should be doing something differently, like adding the controls in Page_Init but then the Add Button event (cmdAdd_Click) hasn't gone off yet. I can't seem to figure out how to do it in a clean and simple way.
.aspx snippet:
<asp:Button ID="cmdAdd" runat="server" OnClick="cmdAdd_Click" />
<asp:ListBox ID="lboObjects" runat="server"></asp:ListBox>
<asp:Panel ID="pnlButtons" runat="server"></asp:Panel>
.cs code Behind Snippet:
protected void cmdAdd_Click(object sender, ImageClickEventArgs e)
{
// Simplified for Brevity
((List<Line>)Session["lstObjects"]).Add("Unique Object"); // the object will be unique.
lboObjects.DataSource = ((List<Line>)Session["lstObjects"]);
lboObjects.DataBind();
// Clear out b/c I intend on having a cmdRemove_Click, but not showing for simplicity
pnlButtons.Controls.Clear();
foreach (object obj in ((List<Line>)Session["lstObjects"]))
{
ImageButton imageButton = new ImageButton();
imageButton.ID = obj.ToString();
imageButton.Click += cmdChangeColor_Click;
pnlButtons.Controls.Add(imageButton);
}
}
protected void cmdChangeColor_Click(object sender, ImageClickEventArgs e)
{........}
You want to load controls inside Page_Init. Otherwise, they are not in control tree, and they won't be able to trigger cmdChangeColor_Click event.
For example,
protected void Page_Init(object sender, EventArgs e)
{
var list = Session["lstObjects"] as List<Line>;
if (list != null)
{
foreach (var obj in list)
{
ImageButton imageButton = new ImageButton {ID = obj.ToString()};
imageButton.Click += cmdChangeColor_Click;
pnlButtons.Controls.Add(imageButton);
}
}
}

ASP Radiobutton oncheckedchange not firing

I have a custom radiobutton below inside of a repeater and when a user clicks it, it is supposed to fire the code behind, however this is not firing at all. I've placed a breakpoint at the beginning of the method and it isnt ever reached. The only thing that does happen is a postback of the updatepanel
<EclipseUI:CustomRadioButton runat="server" ID="RadioButton_Select"
ClientIDMode="AutoID" ToolTip='<%# "id_" + Eval("FeaturePackId") %>' GroupName='<%# "id_" + Eval("FeaturePackId") %>'
OnCheckedChanged="RadioButton_Select_OnCheckedChanged" AutoPostBack="True"/>
The code behind is simply this, it takes the value of each checked radiobutton and places it in a hidden field for use later.
protected void RadioButton_Select_OnCheckedChanged(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.Clear();
foreach (RepeaterItem repeaterItem in Repeater_Select.Items)
{
CustomRadioButton radioButton = repeaterItem.FindControl("RadioButton_Select") as CustomRadioButton;
if (radioButton != null)
{
if (radioButton.Checked)
{
sb.Append(radioButton.GroupName.Substring(4));
}
else
{
sb.Replace(radioButton.GroupName.Substring(4), "");
}
}
}
HF_Feature.Value = sb.ToString();
}
My problem is that this doesnt fire at all.
EDIT
My code is now as follows, and the item databound event is hit and so is the += assignment of the eventhandler to the radiobutton but clicking the radiobutton still doesnt hit my breakpoint in the OnCheckedChange of the radiobutton method:
protected void Page_Load(object sender, EventArgs e)
{
Repeater_Select.ItemDataBound += new RepeaterItemEventHandler(Repeater_Select_OnItemDataBound);
}
protected void Repeater_Select_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
CustomRadioButton customRbtn = (CustomRadioButton)e.Item.FindControl("RadioButton_Select");
customRbtn.CheckedChanged += new EventHandler(RadioButton_Select_OnCheckedChanged);
}
}
But it is still not working
in a repeater you will have to wire up the OnCheckedChanged events inside of the repeaters _ItemDataBound.
protected void Page_Init(object sender, EventArgs e
{
myRepeater.ItemDataBound += new RepeaterItemEventHandler(myRepeater_ItemDataBound);
}
and then..
private void myRepeater_ItemDataBound(object sender, RepeaterCommandEventArgs e)
{
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType !=
ListItemType.AlternatingItem)
{
CustomRadioButton customRbtn = (CustomRadioButton)e.Item.FindControl("RadioButton_Select");
//Now you have an instance of your eclipse radio button so you can do what you want with it.
}
}
Have a looksy at this: OnCheckedChanged event handler of asp:checkbox does not fire when checkbox is unchecked
at at way the "_ItemDataBound" is wired up.
and this article may be a little closer to your problem if your using item template in the .aspx file. http://www.codeguru.com/csharp/.net/net_asp/tutorials/article.php/c12065/ASPNET-Tip-Use-the-ItemDataBound-Event-of-a-Repeater.htm
Just try to setting CauseValidation="false" (besides Autopostback="true")
<EclipseUI:CustomRadioButton runat="server" ID="RadioButton_Select" ClientIDMode="AutoID" ToolTip='<%# "id_" + Eval("FeaturePackId") %>' GroupName='<%# "id_" + Eval("FeaturePackId") %>' OnCheckedChanged="RadioButton_Select_OnCheckedChanged" AutoPostBack="True" CauseValidation="false"/>
It works...

Gridview - Reference to a new column

I have a gridview which takes in data from 3 tables.
And this gridview also have an additional column called "Role" which is not included in the database.
Currently, without adding any logic but simply using the findcontrol to the label, "Role", i can show out "ML"
But, when I add in the logic, it did not appear at all.
In any case, does anyone knows how to insert "ML" into the "Role" column which is not found in the database but is reference from another column found in the database.
This is the codes used to display the "ML" in the role column.
protected void gridAMDisplay_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//find the Label control using FindControl and set its Text on some column value
DataRowView row = (DataRowView)e.Row.DataItem;
if (!DBNull.Value.Equals(row["ModuleLeader"]))
{
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
Label lbl = e.Row.FindControl("lblRole") as Label;
if (lbl != null)
{
lbl.Text = "ML";
}
}
}
}
}
This part of the code when comment off, the ML can be displayed in the role column, otherwise, nothing is displayed.
Therefore, i feel that the findcontrol part works. BUT, referencing does not works.
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
As i mentioned, the role column was not included in any of the tables in the DB.
Therefore, i added in this codes.
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text="" />
</ItemTemplate>
</asp:TemplateField>
But, the problem i have now is, the role column does not reference to the column it is supposed to, which is "Module Leaders"
You reference the DataItem, which cannot be used in DataBound, you should use OnDataBinding to implement this.
It seems you only want the role column to update to "ML" based on the data present in another column of the same row. Why not just drop it in the XHTML?
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text='<%# GetRoleString(Eval("ModuleLeader"))%>' />
</ItemTemplate>
</asp:TemplateField>
Then in the code behind you could have a method:
string GetRoleString(string moduleLeader)
{
return (moduleLeader == "ModuleStr") ? "ML" : "";
}
This would occur on databinding and would only happen once per row.
The best practice in my humble opinion is to create your own template.
Here is one for your case :
public class NotEmptyValueFromDataTemplate : System.Web.UI.Page, IBindableTemplate
{
protected string p_DataFieldToLookAt;
protected string p_ValueToPlaceInIfNotNull;
protected Literal p_litControl;
public RoleTemplate(string DataFieldToLookAt, string ValueToPlaceInIfNotNull)
{
this.p_DataFieldToLookAt = DataFieldToLookAt;
this.p_ValueToPlaceInIfNotNull = ValueToPlaceInIfNotNull;
}
public virtual void OnInit(object sender, EventArgs e)
{ }
#region IBindableTemplate Members
public System.Collections.Specialized.IOrderedDictionary ExtractValues(Control container)
{
throw new NotImplementedException();
}
#endregion
#region ITemplate Members
public void InstantiateIn(Control container)
{
p_litControl = new Literal();
p_litControl.ID = p_DataFieldToLookAt; /* we don't really care */
p_litControl.Init += new EventHandler(OnInit);
p_litControl.DataBinding += new EventHandler(p_litControl_DataBinding);
container.Controls.Add(p_litControl);
}
void p_litControl_DataBinding(object sender, EventArgs e)
{
var Data = ((GridViewRow)(p_litControl.NamingContainer)).DataItem;
string ValueFromData = Convert.ToString(DataBinder.Eval(Data, p_DataFieldToLookAt));
if(!String.IsNullOrEmpty(ValueFromData))
p_litControl.Text = p_ValueToPlaceInIfNotNull;
}
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
}
#endregion
}
You have then to instantiate each template row :
protected void GridView3_Init(object sender, EventArgs e)
{
((TemplateField)(GridView3.Columns[/* Column Index Here*/])).ItemTemplate = new NotEmptyValueFromDataTemplate("ModuleLeader", "ML");
}
Last, create the template item in the gridview :
<asp:TemplateField HeaderText="Role"></asp:TemplateField>
PS : Code is untested and written out of solution

Find control in ListView EmptyDataTemplate

I have the a ListView like this
<asp:ListView ID="ListView1" runat="server">
<EmptyDataTemplate>
<asp:Literal ID="Literal1" runat="server" text="some text"/>
</EmptyDataTemplate>
...
</asp:ListView>
In Page_Load() I have the following:
Literal x = (Literal)ListView1.FindControl("Literal1");
x.Text = "other text";
but x returns null. I’d like to change the text of the Literal control but I don’t have no idea how to do it.
I believe that unless you call the DataBind method of your ListView somewhere in code behind, the ListView will never try to data bind. Then nothing will render and even the Literal control won’t be created.
In your Page_Load event try something like:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//ListView1.DataSource = ...
ListView1.DataBind();
//if you know its empty empty data template is the first parent control
// aka Controls[0]
Control c = ListView1.Controls[0].FindControl("Literal1");
if (c != null)
{
//this will atleast tell you if the control exists or not
}
}
}
You can use the following:
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.EmptyItem)
{
Control c = e.Item.FindControl("Literal1");
if (c != null)
{
//this will atleast tell you if the control exists or not
}
}
}
It's not specifically what you asked, but another way to do that kind of thing is like this:
<EmptyDataTemplate>
<%= Foobar() %>
</EmptyDataTemplate>
where Foobar is defined in your page's code behind file
public partial class MyClass : System.Web.UI.Page
{
...
public string Foobar()
{
return "whatever";
}
}
An alternative approach...
<asp:ListView ID="ListView1" runat="server">
<EmptyDataTemplate>
<asp:Literal ID="Literal1" runat="server" text="some text" OnInit="Literal1_Init" />
</EmptyDataTemplate>
...
</asp:ListView>
In code-behind...
protected void Literal1_Init(object sender, EventArgs e)
{
(sender as Literal).Text = "Some other text";
}
Protected Sub ListView1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs) Handles ListView1.ItemDataBound
Dim searchValue As String = Replace(Request.QueryString("s"), "", "'")
Dim searchLiteral2 As Literal = CType(ListView1.FindControl("Literal2"), Literal)
searchLiteral2.Text = "''" & searchValue & "''"
End Sub
...
Answering Broam's question "Is there any way to do this in the databound method? I'd rather not hardcode "controls[0]" as that's sloppy"
protected void ListView1_DataBound(object sender, EventArgs e)
{
ListView mylist = ((ListView)sender);
ListViewItem lvi = null;
if (mylist.Controls.Count == 1)
lvi = mylist.Controls[0] as ListViewItem;
if (lvi == null || lvi.ItemType != ListViewItemType.EmptyItem)
return;
Literal literal1 = (Literal)lvi.FindControl("Literal1");
if (literal1 != null)
literal1.Text = "No items to display";
}
Unfortunately, I've not found a way to not use Controls[0].
In the usual Item events (ItemDataBound or ItemCreate), you can use e.Item of the ListViewItemEventArgs to get the ListViewItem. In the DataBound event, there's only a generic EventArgs.
And on top of that, it seems that ((Control)sender).FindControl("Literal1") doesn't work either (find control from the listview at the top of the tree), hence the use of Controls[0] .FindControl(...) (find control from the listviewitem).

Categories

Resources