I have a simple repeater that gets the 'groups' of 'widgets' The home page lists all of the groups:
<ItemTemplate>
<tr>
<td width="60" class="center"><%# DataBinder.Eval(Container.DataItem, "Number") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Name") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Description") %></td>
</tr>
</ItemTemplate>
Code Behind
private void LoadForm()
{
using (MarketingWebContentEntities context = new MarketingWebContentEntities())
{
rptGroup.DataSource = (from groups in context.URLGroup
select groups).ToList();
rptGroup.DataBind();
}
}
I would like within the repeater to show number of 'widgets' within each 'group'. I know I'd need to run a query on the 'widgets' table to see how many items are in that list. I'm just unsure how to add that within the repeater mark-up.
As mentioned in the comment, you could use the ItemDataBound event for this.
This example is in VB - been a while since I wrote C#, though will give you an idea. I haven't checked it for syntax either, it's more an example to get you up and running.
In your <ItemTemplate> add yourself, say, a ASP:Label. In this case, it's called myLabel
So in your code behind, create a private method that will handle the ItemDataBound event.
Protected Sub myRepeater_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles myRepeater.ItemDataBound
If (e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim uG As URLGroup = CType(e.Item.DataItem, URLGroup)
'' you now have the group for that one item
'' you should now be able to get additional information needed.
'' you can also get the myLabel from this item
dim lbl as Label = CType(e.Item.FindControl("myLabel", Label)
'' and set its text to whatever you need
lbl.Text = MyCounter
End If
End Sub
Hopefully this will get you on your way.
Here is a link to the MSDN documentation for it too.
I used the OnItemDataBount event
<asp:Repeater runat="server" ID="rptGroup" OnItemDataBound="rptDestinationCount_ItemDataBound">
<HeaderTemplate>
<table id="tblUrlGroup" class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th style="width:20px;">Count</th>
<th style="width:35px;">Add</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><i class="icon-wrench" rel="tooltip" title="Edit Group Name"></i> <%# DataBinder.Eval(Container.DataItem, "Name") %></td>
<td class="center"><asp:HiddenField runat="server" ID="hidURLGroupRowID" Value='<%# DataBinder.Eval(Container.DataItem, "URLGroupRowID") %>' /><asp:Label runat="server" ID="lblCount"></asp:Label></td>
<td class="center">
<i class="icon-plus" rel="tooltip" title="Manage Destination URLs"></i>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
On the function I made sure I was only looking through the repeater Item and Item Template. The hidden field is set with the ID with the datasource. This allowed me to run a query and set the lblCount.Text to the destination count.
Code Behind
protected void rptDestinationCount_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
using (MarketingWebContentEntities context = new MarketingWebContentEntities())
{
Label lblCount = (Label)e.Item.FindControl("lblCount");
HiddenField hidURLGroupRowID = (HiddenField)e.Item.FindControl("hidURLGroupRowID");
int groupRowID = Convert.ToInt32(hidURLGroupRowID.Value);
var destination = (from dest in context.URLDestination
where dest.URLGroup.URLGroupRowID == groupRowID
select dest).ToList();
lblCount.Text = destination.Count.ToString();
}
}
}
Related
I am trying to set the text of the label control which is inside detailsview but it's not working. But it's showing error "Object reference not set to an instance of an object."
can anyone guide me please.. ??
My front end code is:
<asp:Panel ID="sub_question_panel" runat="server">
<asp:DetailsView ID="DetailsView1" runat="server" CellPadding="6" ForeColor="#333333" AutoGenerateRows="false" GridLines="None" >
<Fields>
<asp:TemplateField>
<ItemTemplate>
<table id="Question_view_table">
<tr>
<td style="font-family:Arial Rounded MT;">
<label id="Question_no"><span style="font-size:20px;">Question</span>:</label>
<asp:Label ID="Ques_id_label" runat="server" Text="Label"></asp:Label></td>
</tr>
<tr>
<td style="height:20px"></td>
</tr>
<tr>
<td style="font-family:'Times New Roman'; font-size:18px; ">
<label id="Question_detail"><%# Eval ("Question") %></label>
</td>
</tr>
<tr>
<td style="font-family:'Times New Roman'; font-size:18px;">
<ol style="list-style:upper-alpha">
<li>
<label id="optn1">   <%# Eval ("Option1") %></label></li>
<li>
<label id="optn2">   <%# Eval ("Option2") %></label></li>
<li>
<label id="optn3">   <%# Eval ("Option3") %></label></li>
<li>
<label id="optn4">   <%# Eval ("Option4") %></label></li>
</ol>
</td>
</tr>
</table>
</ItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
</asp:Panel>
My back end code is:
protected void Page_Load(object sender, EventArgs e)
{
int question_id = 1;
Label Question_Id = DetailsView1.FindControl("Ques_id_label") as Label;
Question_Id .Text = Convert.ToString(question_id);
}
You must use the FindControl for a row, not DataListView
You want to find your label by id, But which one? For each row you have a label with id 'Ques_id_label' . So to find a specific label you must specify the intended row. I did not work with DataLisView but I know that it is logically similar to Asp:Repeater . To find a control in a row of a Repeater when a command is sent from a row:
protected void SaveAnswer(Object Sender, RepeaterCommandEventArgs e)
{
Label Ques_id_label = (Label)e.Item.FindControl("Ques_id_label");
Which with e.item you specify the intended row.
You use FindControl to find Ques_id_label, but then reference it normally anyway: Ques_id_label.Text =
It should be Question_Id.Text = Convert.ToString(question_id);, with the ID you assigned with FindControl.
But did it even compile? Do you use an editor like Visual Studio? Because when I tried your snippet it gave the error The name 'Ques_id_label' does not exist in the current context, as it is supposed to.
I'm trying only to show the repeater separator when the column named "date" from the previous item differs from the current item date.
Code below is only to facilitate the clarification of my doubt.
I have a repeater like this:
<asp:Repeater ID="tbData" runat="server">
<HeaderTemplate>
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Description</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# DataBinder.Eval(Container.DataItem, "Date") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Description") %></td>
</tr>
</ItemTemplate>
<SeparatorTemplate>
<tr id="rowSeparator" runat="server" visible="false">
<td></td>
<td></td>
</tr>
</SeparatorTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
I need only to show separator when previous date differs from current.
Date Description
28/03/2016 Sample
28/03/2016 Sample
=> Here separator is showed.
29/03/2016 Sample
I've tried something like this:
private DateTime? lastShowedDate = null;
public bool isOtherDate;
...
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Separator)
{
//Compare last and current date
isOtherDate = ((MyType)e.Item.DataItem).MyDate.Date != lastShowedDate.Value.Date;
//Save current date for next item comparison
lastShowedDate = ((MyType)e.Item.DataItem).MyDate;
//Find and set control visibility
Control separator = (Control)e.Item.FindControl("rowSeparator");
separator.Visible = isOtherDate;
}
}
Try binding the visibility of the separator with a bool value. When you fill the data to bind, make the required logic in order to add a True or False.
Hiding the separator is actually easier than you may think. Just simply set the visibility of the item to false. Assuming the date comparison logic works correctly, it looks like you have everything else already done.
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Separator)
{
//Compare last and current date
isOtherDate = ((MyType)e.Item.DataItem).MyDate.Date != lastShowedDate.Value.Date;
//Save current date for next item comparison
lastShowedDate = ((MyType)e.Item.DataItem).MyDate;
e.Item.Visible = isOtherDate;
}
}
Please consider these operations -
Bind a list of files in a DataList.
Once the user clicks delete LinkButton, delete the file, in
ItemCommandEvent.
Since rebinding whole data is inefficient, I am simply hiding
deleted row.
Following code displays files in a DataList. There is a delete button beside each row.
<asp:DataList ID="DataList1" OnItemCommand="DataList1_ItemCommand" runat="server">
<ItemTemplate>
<tr>
<asp:Label Text='<%# Eval("ContainingFolder") as string + "\\" + Eval("FileName") as string %>'
Visible="false" ID="lblFullPath" runat="server" />
<td><%# Eval("FileName") %></td>
<td><%# Eval("ContainingFolder") %></td>
<td><%# Eval("FileSize") %></td>
<td><%# Eval("Modified") %></td>
<td>
<asp:LinkButton Text="Delete" ID="linkDelete" runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:DataList>
In ItemCommand Event Handler this code deletes the selected file from this list.
protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e)
{
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem) return;
var selectedItem = e.Item.FindControl("lblFullPath") as Label;
e.Item.Visible = false; //doesn't work
File.Delete(selectedItem.Text);
}
However e.Item.Visible = false does not hides the row.
As a workaround found here, How to hide an item in datalist
I have wrapped contents inside a placeholder control.
<ItemTemplate>
<asp:PlaceHolder ID="ph1" runat="server">
<%--wrapped content--%>
</asp:PlaceHolder>
</ItemTemplate>
And hiding the placeholder control -
protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e)
{
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem) return;
var selectedItem = e.Item.FindControl("lblFullPath") as Label;
//e.Item.Visible = false;
e.Item.FindControl("ph1").Visible = false;
File.Delete(selectedItem.Text);
}
Generally in asp.net hiding parent control hides all of its child controls.
But I am not able to understand,
Why hiding the parent control e.Item doesn't hide its containing
elements, in case of DataList ? Can you please advise.
Thank you for your help.
EDIT: Updating more info about generating list of files to display in DataList.
Generating fileList at runtime on button click, this list is not
persistent, currently.
protected void btnFindDuplicates_Click(object sender, EventArgs e)
{
DataList1.DataSource = FindDuplicates();
DataList1.DataBind();
}
In the event handler of delete Click, delete operation has been
completed successfully.
So, just to remove deleted item from the page, It would not be wise
to regenerate the dataSource and bind this. Hiding seems more logical to me.
I created this sample using JQuery and PageMethods:
Result
ASPX
<script>
$(function () {
var $list = $("table[id*=myDataListID]");
var $buttons = $("input:submit[id*=remove]", $list);
$buttons.click(function (e) {
e.preventDefault();
if (!confirm("Are you sure?")) {
return false;
}
var $self = $(this);
var $jobID = $self.closest("tr").children().find("span[id*=jobID]");
$buttons.prop("disabled", true);
$.ajax({
url: "<%: this.ResolveClientUrl("~/Topics/JQuery/Ajax/RemoveRowUsingJQueryAfterCallingService.aspx/Remove") %>",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{id: " + $jobID.text() + "}",
async: true,
cache: false,
success: function () {
$buttons.prop("disabled", false);
$self.closest("tr").remove();
},
error: function (XHResponse, errorMessage, errorCode) {
$buttons.prop("disabled", false);
alert(errorMessage);
}
});
});
});
</script>
<asp:DataList runat="server" DataKeyField="job_id" DataSourceID="lds" ID="myDataListID">
<HeaderTemplate>
<tr>
<th>
</th>
<th>
ID
</th>
<th>
Name
</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Button Text="Remove" runat="server" ID="remove" />
</td>
<td>
<asp:Label Text='<%# Eval("job_id") %>' runat="server" ID="jobID" />
</td>
<td>
<asp:Label ID="jobDesc" Text='<%# Eval("job_desc") %>' runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:DataList>
Code behind
[WebMethod]
public static void Remove(Int16 id)
{
// simulate deleting the file
Thread.Sleep(3000);
}
I just uploaded the full working example to my GitHub site
The following is the design.
<table>
<tr>
<td>Project Title</td>
<td>Download Link</td>
</tr>
<tr>
<td><asp:Label ID="dlLbl" runat="server"></asp:Label></td>
<td><asp:Label ID="dlLink" runat="server"></asp:Label></td>
</tr>
</table>
And the following is the backend codes.
foreach (SPListItem objInnovationListItem in objInnovationList.Items)
{
if (Convert.ToString(objInnovationListItem["Innovation Approval Status"])== status)
{
countStatus++;
//Displays name of the document and download link
dlLbl.Text = objInnovationListItem["Project Title"].ToString();
dlLink.Text = "<a href='/RIDepartment/Innovation%20Submission/" + objInnovationListItem.File.Name + "'>Download</a><br>";
}
}
Hence, my question is, what can I do to allow the tables to dynamically accommodate the document and dl link when there's more than 1 in the loop?
Appreciate some code samples.
With your code style (manual creating html without web-controls) i recommend you to look on ASP.NET MVC side. But i can answer to your question:
First - you need to use asp:Repeater like this:
<table>
<tr>
<td>Project Title</td>
<td>Download Link</td>
</tr>
<asp:Repeater ID="repLinks" runat="server"
onitemdatabound="repLinks_ItemDataBound">
<ItemTemplate>
<tr>
<td>
<asp:Label ID="lblProject" runat="server" Text="Label"></asp:Label>
</td>
<td>
<asp:HyperLink ID="hlLink" runat="server">HyperLink</asp:HyperLink>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
second: you need to initialize your collection, that you want to display. For example: you want to display a collection of objInnovationListItem class:
public class objInnovationListItem
{
public string Name { get; set; }
public string Title { get; set; }
public override string ToString()
{
return Title;
}
}
you need do next:
// list - it's source List<objInnovationListItem>
var bindList = list.Where(p => objInnovationListItem["Innovation Approval Status"] == status); // filter your collection - replace you foreach and if statement
repLinks.DataSource = bindList; // set to repeater your displayed collection
repLinks.DataBind(); // bind your collection
and last - you need to indicate in your Repeater ItemTemplate how to display your objInnovationListItem instance - subscribe to event of your Repeater ItemDataBound:
protected void repLinks_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var item = e.Item.DataItem as objInnovationListItem;
((Label) e.Item.FindControl("lblProject")).Text = item.Name;
((HyperLink) e.Item.FindControl("hlLink")).NavigateUrl = string.Format("/downloaduri?id={0}", item.Title);
}
Result will look like that:
I would use a repeater... Something like this (code might not be exact):
<table>
<tr>
<td>Project Title</td>
<td>Download Link</td>
</tr>
<asp:Repeater id="rptItems" runat="server">
<ItemTemplate>
<tr>
<td><asp:Label ID="dlLbl" runat="server"></asp:Label></td>
<td>Download<br></td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
and then in the ItemDataBound event of the repeater, do something like this:
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
((Label)e.Item.FindControl("dlLbl")).Text= ((SPListItem)e.Item.DataItem)["Project Title"].ToString();
}
Why don't you skip the server side controls, and just write the actual html?
Include this div in your aspx file:
<div runat="server" id="divTable"></div>
And put this in your Page_Load():
StringBuilder sb = new StringBuilder();
sb.Append("<table><tr><td>Project Title</td><td>Download Link</td></tr>");
for (int i = 0; i < 10; i++)
{
sb.AppendFormat("<tr><td>{0}</td><td><a href='{1}'>{1}</a></td></tr>", "Title", "Link");
}
sb.Append("</table>");
divTable.InnerHtml = sb.ToString();
You'll of course need to replace "Title" and "Link" with the appropriate values.
Your other options is to actually create new labels and links, but ASP.net is notoriously difficult to work with when you create your server side controls dynamically.
Given the following HTML:
<asp:content id="Content1" contentplaceholderid="mainContent" runat="server">
<div class="scrollRow">
<table width="100%">
<tr>
<td width="25%">Site name: <b>My site</b></td>
<td>Created on 12th Aug 2010</td>
<td align="right"><button onclick="doRevert(1)">Revert to this</button></td>
</tr>
</table>
</div>
<div class="scrollRow">
<table width="100%">
<tr>
<td width="25%">Site name: <b>Another site</b></td>
<td>Created on 3rd Aug 2010</td>
<td align="right"><button onclick="doRevert(1)">Revert to this</button></td>
</tr>
</table>
</div>
<div class="scrollRow scrollRowOn">
<table width="100%">
<tr>
<td width="25%">Site name: <b>Another site</b></td>
<td>Created on 3rd Aug 2010</td>
<td align="right"></td>
</tr>
</table>
</div>
</asp:content>
Which is a list of rows, how am I programatically meant to generate these after I have retrieved the SQL rows from the code behind? Do I need to make my own control, or something along those lines?
Try something along these lines:
<asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_OnItemDataBound">
<ItemTemplate>
<div class='<%# SetClass(Eval("SiteId")) %>'>
<table width="100%">
<tr>
<td width="25%">Site name: <b><%# Eval("SiteName") %></b></td>
<td>Created on <%# DataBinder.Eval(Container.DataItem, "CreateDate", "{0:dd MMM yyyy}")%></td>
<td align="right"><button id="btnRevert" runat="server" onclick="doRevert(1)">Revert to this</button></td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:Repeater>
In the codebehind Repeater1_OnItemDataBound event you could set the button to be visible or not, depending on whether the item is the current one.
protected void Repeater1_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item.ItemType == ListItemType.AlternatingItem || item.ItemType == ListItemType.Item)
{
Site site = e.Item.DataItem as Site; //List<Site> is what you are binding to the repeater
if (site.SiteId == currentSiteId)
{
var btn = e.Item.FindControl("btnRevert") as Button;
if (btn != null)
{
btn.Visible = false;
}
}
}
}
CSS Classes for your items can be set like this:
protected string SetClass(object obj) {
int siteId;
if (int.TryParse(obj.ToString(), out siteId)){
if (siteId == currentSiteId) //currentSiteId determined elsewhere
{
return "scrollRow";
}
}
return "scrollRow scrollRowOn";
}
There are a lot of ways to get to this, of course, but here's one (possibly not the best, but that's subjective anyway):
Assuming C# web forms and ADO.Net, and assuming you need precisely that html, you could loop over the rows in the DataSet and output the html.
DataSet ds = {data set from your sql}
StringBuilder html = new StringBuilder();
foreach (DataRow row in DataSet.Tables[0].Rows) {
html.Append( string.Format(#"<div class=""scrollRow"">
<table width=""100%"">
<tr>
<td width=""25%"">Site name: <b>{0}</b></td>
<td>Created on {1}</td>
<td align="right"><button onclick="doRevert(1)">Revert to this</button></td>
</tr>
</table>",row["sitename"], row["createdate"]));
}
You could include the html by having an <asp:Literal> in the page code and setting the Text property.
You could also do it by creating System.Web.UI.WebControls.Table nodes in the code behind and adding TableRows and TableCells to them, using the same loop, and then adding those to the page using. Given what you've given us thus far, you seem to be adding controls to a page with a MasterPage, so you would need to add your tables to the Master's ContentPlaceHolder, which you can find and add controls to like so:
ContentPlaceHolder ph = (ContentPlaceHolder)this.Master.FindControl( "ContentPlaceHolder1" );
foreach (DataRow row in DataSet.Tables[0].Rows) {
Panel pnl = new Panel();
Table tbl = new Table();
TableRow tblrow = new TableRow();
TableCell cell1 = new TableCell();
cell1.Text = string.Format("Site name: <b>{0}</b>",row["sitename"]);
row.Cells.Add(cell1);
tbl.Rows.Add(tblrow);
pnl.Controls.Add(tbl);
ph.Controls.Add(pnl);
}
You can set properties on the TableRows and TableCells, but if you do it this way you will lose some control over the html that's generated, most notably the html ID attributes. You don't seem to be using those, so perhaps that's ok.
I would suggest the repeater control. You can use it something like this:
<asp:Repeater runat="server" id="myRepeater">
<ItemTemplate>
<div class="scrollRow scrollRowOn">
<table width="100%">
<tr>
<td width="25%">Site name: <b><% Eval("SiteName")%></b></td>
<td>Created on <% Eval("CreatedOn")%></td>
<td align="right"></td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:Repeater>
Then you need to bind your data to it in the Page_Load event:
myRepeater.DataSource = myData;
myRepeater.DataBind();
Where my data is the data that you retrieve from the database.