I have a table cell that I fill with CheckBoxes and Labels at runtime.
List<string> lstUserPool = new List<string>();
DataTable dt = GetData("SELECT UserName FROM eData ORDER BY UserName;", "Data Source = lewcomp1\\COMPLIANCE; Initial Catalog = ComplianceData; Integrated Security = True;");
for (int i = 1; i < dt.Rows.Count; i++)
{
CheckBox cb = new CheckBox();
cb.ID = "cb" + dt.Rows[i]["Username"].ToString();
Label lbl = new Label();
lbl.ID = "lbl" + dt.Rows[i]["Username"].ToString();
lbl.Text = dt.Rows[i]["Username"].ToString();
lbl.Font.Size = new FontUnit("18px");
if (IsOdd(i))
{
cellUsersPoolLeft.Controls.Add(cb);
cellUsersPoolLeft.Controls.Add(lbl);
cellUsersPoolLeft.Controls.Add(new LiteralControl("<br/>"));
}
if (IsEven(i))
{
cellUsersPoolRight.Controls.Add(cb);
cellUsersPoolRight.Controls.Add(lbl);
cellUsersPoolRight.Controls.Add(new LiteralControl("<br/>"));
}
}
Later, I'd like to loop through these Checkboxes to check what is Checked and what is not. I've tried various examples found on SO but with no luck. It's almost as if the checkboxes are not in the TableCell that I'v added them to. Both of the below loops do not find any checkbox controls:
foreach (Control ctl in cellUsersPoolRight.Controls)
{
if (ctl is CheckBox)
{
}
}
//foreach(var checkBox in cellUsersPoolRight.Controls.OfType<CheckBox>())
//{
// if (checkBox.Checked)
// {
// naz.Add(checkBox.ID);
// }
//}
I suggest you use a Repeater and Databind a Checkbox and Label to ItemTemplate in the repeater. This will easily allow you to get the data by looping through the repeater. If you need additional data add Hiddenfield within the repeater to store them.
<asp:Repeater ID="UserRepeater" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:CheckBox ID="UserCheckBox" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsUserChecked")) %>' ToolTip='<%# Eval("UserId") %>'
onmouseover="title='';" />
</td>
<td>
<asp:Label ID="UserNameLabel" runat="server" Text='<%# Eval("UserName") %>'></asp:Label>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
Then in your codebehind
//initialize repeater data
userRepeater.DataSource = dt;
userRepeater.DataBind();
Then in postback of your imagebutton_click you can get the items from the repeater
foreach (RepeaterItem ri in UserRepeater.Items)
{
CheckBox userCheckBox = ri.FindControl("UserCheckBox") as CheckBox;
}
Sorry, I cannot write in comments yet.
On which event are you trying to add the control and on which are you trying to read from it?
Take a look at this post to read more.
check the order of events on page, and if you are using the correct event in the life cycle.
Related
I have a datalist which is populated with values from a database. When the user clicks a checkbox, I want to loop through all of the datalist items and hide all of the items that have the property isActive = false (which is displayed as "Disabled" in a text label). The item template consists of a table that contains multiple other items, buttons etc, which have not been included below. I therefore want to hide all elements that are found under the itemtemplate of a specific item.
My idea was to just hide the entire table by accessing its id, and then setting the table's visible property to false. This is currently not doing anything when I run the code. Any help will
appreciated!
<asp:CheckBox runat="server" Text="Filter by active postings" OnCheckedChanged="filterByActive"/>
<asp:DataList ID="postingsDataList" runat="server" OnItemCommand="itemCommand" >
<ItemTemplate>
<div class="postingRow">
<table class="postingTable" id="posting">
<tr>
<td>
<asp:Label ID="lblActive" runat="server" Text=<%#Eval("isActive").ToString().Equals("True") ? "Active ✅" : "Disabled ❌"%>/>
</td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:DataList>
Code Behind:
protected void filterByActive (object sender, EventArgs e)
{
int count = postingsDataList.Items.Count;
CheckBox check = (CheckBox)sender;
if (check.Checked == true)
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Disabled ❌"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = false;
}
}
}
else
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Active ✅"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = true;
}
}
}
}
}
Ok, I suggest you do this:
Persist your table - thus you don't have to hit sql server again. (but, you could - not the end of the world).
I don't have your data, but I have a simple list of hotels - and there is a Active column for the Hotel. So, lets filter the data based on checking the check box, not have to hit the database server again. And EVEN BETTER is if we un-check the box, we can display all records we had.
We assume of course this is not a lot of data.
Ok, so we have this for our markup:
(really does not matter a whole lot)
<asp:DataList ID="DataList1" runat="server" DataKeyField="ID" RepeatColumns="4" RepeatDirection="Horizontal" >
<ItemTemplate>
<div style="border-style:solid;color:black;width:300px;">
<div style="padding:5px;text-align:right">
<p>Hotel Name: <asp:TextBox ID="HotelName" runat="server" Text ='<%# Eval("HotelName") %>' /></p>
<p>First Name: <asp:TextBox ID="FirstName" runat="server" Text ='<%# Eval("FirstName") %>' /></p>
<p>Last Name: <asp:TextBox ID="LastName" runat="server" Text ='<%# Eval("LastName") %>' /></p>
<p>City: <asp:TextBox ID="City" runat="server" Text ='<%# Eval("City") %>' /></p>
<p>Province: <asp:TextBox ID="Province" runat="server" Text ='<%# Eval("Province") %>' /></p>
Active: <asp:CheckBox ID="Active" runat="server" Checked = '<%# Eval("Active") %>'/>
</div>
</div>
</ItemTemplate>
</asp:DataList>
Now, our code to load could be this:
DataTable rstData = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadData();
ViewState["MyData"] = rstData;
}
else
rstData = (DataTable)ViewState["MyData"];
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT top 10 * from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
DataList1.DataSource = rstData;
DataList1.DataBind();
}
}
}
And now we have this:
Now, our filter show/hide becomes JUST this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
// filter based on check box
if (ckFilter.Checked)
rstData.DefaultView.RowFilter = "Active = 1";
else
rstData.DefaultView.RowFilter = "";
DataList1.DataSource = rstData;
DataList1.DataBind();
}
And BETTER is if I un-check the check box, all the data is re-displayed. And we don't have to re-hit the database to do this!!!
Now, we COULD also just hide/show each row, and then un-hide if for some reason you don't want to persist the data table as I did per above.
Checking on the box filters to this:
As noted, if I un-check the box, then I get all the data back - all without hitting the database again.
Edit:=========================================
Note that if you NOT using the above horizontal across, but just rows down?
Then you can just as well format to hide/show the rows, and you do NOT have to persist the data table.
You can apply formatting say by doing this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
foreach (DataListItem gRow in DataList1.Items)
{
// get checkbox
CheckBox ckActive = (CheckBox)gRow.FindControl("Active");
// get div
HtmlGenericControl Myiv = (HtmlGenericControl)gRow.FindControl("myrow");
string MyFormat = "normal";
if (ckFilter2.Checked)
{
// only show active ones
if (ckActive.Checked)
MyFormat = "normal";
else
MyFormat = "none";
}
Myiv.Style["display"] = MyFormat;
}
}
So the above does work fine. BUT the restriction is that you can't have a set of horizontal across data items like my original screen shot
(it actually still works but in fact hide each panel with a blank space).
So, if your as noted using vertical layout (and it looks to be that you are).
Note for above, I added a simple ID to the "div", and runat server like this:
<ItemTemplate>
<div id="myrow" runat="server"
style="border-style:solid;color:black;width:300px;">
Then skip my first example. You can loop the data list rows, and hide, or un-hide. And even more amazing is that if you un-hide - then the rows all do re-appear and persist correct.
I had pulled a working example - but I was trying to figure out why I had to persist the data - the reason was the "horizontail" across settings.
But, as above shows, no real need to persist the data source table - you can process the data list rows, and hide/show each one conditionals, and you can do this without a data re-bind.
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.
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
}
}
I have a gridview that has link and description to be rendered on the page.
written the below code in gridview in .aspx
<Columns>
<asp:TemplateField>
<ItemTemplate>
<p>
<asp:HyperLink ID="hlLink" runat="server" Target="_self"></asp:HyperLink></p>
</ItemTemplate>
<ItemTemplate>
<p>
<asp:Literal ID="litSummary" runat="server"></asp:Literal></p>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<AlternatingItemTemplate>
<p>
<asp:HyperLink ID="hlLink" runat="server" Target="_self"></asp:HyperLink></p>
</AlternatingItemTemplate>
<AlternatingItemTemplate>
<p>
<asp:Literal ID="litSummary" runat="server"></asp:Literal></p>
</AlternatingItemTemplate>
</asp:TemplateField>
</Columns>
and below in .aspx.csin gridview rowdataboundevent
protected void gvResults_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
SearchResultItem data = (SearchResultItem)e.Row.DataItem;
HyperLink hlLink = (HyperLink)e.Row.FindControl("hlLink");
Literal litSummary = (Literal)e.Row.FindControl("litSummary");
if (data.Description != null)
{
hlLink.Text = data.Title;
hlLink.NavigateUrl = data.Path.Replace("&", "&");
litSummary.Text = data.Description;
}
else
{
hlLink.Text = data.Path;
hlLink.NavigateUrl = data.Path.Replace("&", "&");
litSummary.Text = data.Path;
}
}
here SearchResultItem: is the result item that has link and description details.
First time when row bound event is called, it binds the data correctly, second time when called throws error "Multiple controls with the same ID 'hlLink' were found. FindControl requires that controls have unique IDs.
Please let me know whats error with the code.
Thanks
Problem : you are trying to create the same controls with same ID multiple times.
Solution : you need to remove the controls before creating them.
Try This:
void RemoveControls()
{
HyperLink l1 = (HyperLink)Page.FindControl("hlLink");
Literal l2 = (Literal)Page.FindControl("litSummary");
if(l1!= null)
Page.Controls.Remove(l1);
if(l2!= null)
Page.Controls.Remove(l2);
}
Solution 2: Pagination for Repeater control.
for implementing pagination in Repeater control you need to create PagedDataSource.
Try This:
PagedDataSource pds = new PagedDataSource();
pds.DataSource = ds.Tables[0].DefaultView;
pds.AllowPaging = true;
pds.PageSize = 8;//page sizes
I have a standard Repeater and all I want to do is add paging to it and I keep getting the error listed in the title. Here is what my error points to
private void ItemsGet()
{
// Read sample item info from XML document into a DataSet
DataSet Items = new DataSet();
Items.ReadXml(MapPath("Items.xml"));
// Populate the repeater control with the Items DataSet
PagedDataSource objPds = new PagedDataSource();
objPds.DataSource = Items.Tables[0].DefaultView;
objPds.AllowPaging = true;
objPds.PageSize = 3;
objPds.CurrentPageIndex = CurrentPage;
lblCurrentPage.Text = "Page: " + (CurrentPage + 1).ToString() + " of "
+ objPds.PageCount.ToString();
// Disable Prev or Next buttons if necessary
cmdPrev.Enabled = !objPds.IsFirstPage;
cmdNext.Enabled = !objPds.IsLastPage;
Repeater1.DataSource = objPds;
Repeater1.DataBind();
}
for those that will ask I will post my repeater
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1" OnItemDataBound="myFunction">
<HeaderTemplate>
</HeaderTemplate>
<AlternatingItemTemplate>
</AlternatingItemTemplate>
<ItemTemplate>
</ItemTemplate>
<FooterTemplate>
</FooterTemplate>
</asp:Repeater>
<tr>
<td><asp:label id="lblCurrentPage" runat="server"></asp:label></td>
</tr>
I believe that your're setting the DataSourceID="SqlDataSource1" and also setting the Repeater1.DataSource = objPds;. Set one or the other.
In your case you probably want to remove the DataSourceID="SqlDataSource1"