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).
Related
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
BillingEntity = (string)rdr["BillingEntity"];
string[] split = BillingEntity.Split(',');
for (int i = 0; i < split.Length; i++)
{
split[i] = split[i].Trim();
if (split[i] == "Clinic")
{
BillingEntityCheckBox.Items[i].Checked = true;
Session["billingEntitySessionVar"] = Session["billingEntitySessionVar"]
+ " Clinic";
}
How can I check an item in a checkbox list from the underlying code?
I know with a single checkbox you use checkbox.checked = true. I had that working fine in my code, but I need to link the checkboxes together in a control so that I can trigger an event based on whether any of them has been changed by the user.
To give a little background, I'm pulling in data from a SQL database and outputting to the user interface through a WebForm.
I think you're missing the concept of databinding, is this what you're looking for?:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string[] myStrings = new string[] { "Example Value", "Not a Thing", "Many Things", "All the Thing" };
cblThingy.DataSource = myStrings;
cblThingy.DataBind();
}
protected void btnPushMe_Click(object sender, EventArgs e)
{
//for all the things
foreach(ListItem itemThing in cblThingy.Items)
{
//set a default of not selected
itemThing.Selected = false;
//if the text is the same
//you can have any check you like here
if (itemThing.Text == txtThing.Text)
//say that it's selected
itemThing.Selected = true;
}
}
}
^The "code behind"
<asp:Label ID="lblThing" runat="server" Text="If you type the text and push the button the thing with select." />
<asp:TextBox ID="txtThing" runat="server" Text="Example Value" />
<asp:Button ID="btnPushMe" runat="server" Text="Push My Button" OnClick="btnPushMe_Click" />
<asp:CheckBoxList ID="cblThingy" runat="server" />
^The webform xml
Hopefully that helps!
p.s. I think it would be a good idea to make a readonly property on the BillingEntity type, which would return a bool which does the check for "clinic" inside that class, making it more object oriented..
I was approaching this from the angle of controlling the asp:SqlDataSource bound to the controls inside the formview that is part of this topic and was getting no where rather fast, so I opt'd to close that thread and approach this at the control level inside the formview instead as it seemed to make a lot more sense to me.
So for back ground The code below is intended to inject string values listed in the first two lines of the screen clip below (and the two corresponding Response.Write's at the bottom of the included code block).
What I am trying to do, is use FindControl to set the Text value in the case of these items (but I have a few asp:checkbox's to deal with after getting this done as well that will need the same treatment.) and for now I'm just focusing on these two controls. The first is a asp:label
<asp:Label runat="server" ID="SubmitByLbl" Text='<%# Eval("SubmitBy") %>' ></asp:Label>
The next is a asp:TextBox:
<asp:TextBox Text='<%# Bind("SubmitDT") %>' runat="server" ID="SubmitDTTextBox" />
Both of these are sitting inside of the asp:FormView with an ID="AddItemFv" which has a DataSourceID="AddInvAsset" (which is irrelevant for this discussion but just provided as supplemental info).
Here is the code behind where my problem is:
namespace CInTrac
{
public partial class AddAsset : System.Web.UI.Page
{
protected void Page_Preload(object sender,EventArgs e)
{
AddInvAsset.SelectParameters.Add("SubmitBy", Session["RegUser"].ToString());
AddInvAsset.SelectParameters.Add("SubmitDT", DateTime.Now.ToString("MM/dd/yyyy"));
}
protected void Page_Load(object sender, EventArgs e)
{
Label uname = (Label)AddItemFv.Row.FindControl("SubmitBy");
if (uname != null)
uname.Text = Session["RegUser"].ToString();
TextBox udate = (TextBox)AddItemFv.Row.FindControl("SubmitDT");
if (udate != null)
udate.Text = DateTime.Now.ToString();
Response.Write("<b>Submitted by should be:</b> = " + Session["RegUser"].ToString() + "<br>");
Response.Write("<b>Submit Date should be:</b> = " + DateTime.Now.ToString("MM/dd/yyyy") + "<br>");
}
}
}
The problem that I'm having is Just what you see in the example above; absolutely nothing! I'm new to C# so I am likely doing something wrong with my code here and in debug my trace indicates that as we check for null it then fails to assign value to .Text of each VAR and therefore our values never show up.
Update:
As IM pointed out I had missed the proper name of the controls in the code. Below are the corrections I made to the code above which works fine. Again THanks to Inquisitive_mind for pointing out my error. :
protected void Page_Load(object sender, EventArgs e)
{
Label uname = (Label)AddItemFv.Row.FindControl("SubmitByLbl");
if (uname != null)
uname.Text = Session["RegUser"].ToString();
TextBox udate = (TextBox)AddItemFv.Row.FindControl("SubmitDTTextBox");
if (udate != null)
udate.Text = DateTime.Now.ToString("MM/dd/yyyy");
}
The ID of the controls is incorrect
Change
Label uname = (Label)AddItemFv.Row.FindControl("SubmitBy");
TextBox udate = (TextBox)AddItemFv.Row.FindControl("SubmitDT");
To
Label uname = (Label)AddItemFv.Row.FindControl("SubmitByLbl");
TextBox udate = (TextBox)AddItemFv.Row.FindControl("SubmitDTTextBox");
EDIT
You will have to move the FindControl to a FormView event.The controls will only be accessible after the FormView has been completely created and databound.Try moving the code from page_load to YourFormView_Databound event.
protected void YourFormView_DataBound(Object sender, EventArgs e)
{
Label uname = (Label)AddItemFv.Row.FindControl("SubmitByLbl");
if (uname != null)
uname.Text = Session["RegUser"].ToString();
TextBox udate = (TextBox)AddItemFv.Row.FindControl("SubmitDTTextBox");
if (udate != null)
udate.Text = DateTime.Now.ToString();
}
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.
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