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.
Related
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;
}
}
I've got a ListView control that uses a custom data source. It will be a database soon, but for now I am still trying to get it running.
In the HTML of my form, I have the following code:
<%-- Ref: https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.layouttemplate.aspx --%>
<asp:ListView ID="lvOfficers" runat="server"
OnSelectedIndexChanging="lvOfficers_SelectedIndexChanging"
OnSelectedIndexChanged="lvOfficers_SelectedIndexChanged">
<LayoutTemplate>
<table id="tblOfficers">
<tr>
<th style="width:20%"></th>
<th colspan="2">Member Name</th>
<th style="width:20%"></th>
<th style="width:20%"></th>
</tr>
<tr>
<th>Title</th>
<th>Last</th>
<th>First</th>
<th>Phone</th>
<th>Email</th>
</tr>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:Label ID="lblRank" runat="server" Text='<#Eval("Rank") %>'></asp:Label></td>
<td><asp:Label ID="lblLast" runat="server" Text='<#Eval("LastName") %>'></asp:Label></td>
<td><asp:Label ID="lblFirst" runat="server" Text='<#Eval("FirstName") %>'></asp:Label></td>
<td><asp:Label ID="lblPhone" runat="server" Text='<#Eval("HomePhone") %>'></asp:Label></td>
<td><asp:Label ID="lblEmail1" runat="server" Text='<#Eval("PersonalEmail") %>'></asp:Label></td>
</tr>
</ItemTemplate>
</asp:ListView>
In the code behind with the Page_Load, I populate the data:
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
GetOfficers();
}
}
protected void GetOfficers() {
lvOfficers.DataSource = Personnel.GetOfficers();
lvOfficers.DataBind();
}
I can step through in Debug mode and see that there are 8 elements of type Person in a ListView that my "GetOfficers" data factory churns out.
The Person class contains subclasses:
Phone class: for {Home, Cell, Work},
Address class {Primary, Secondary} that contain ranking logic to indicate contact methods, and
Membership class. One tracks a member's ID, JoinDate, and Expiration while a second instance tracks the same elements for LifeMembership.
Thinking this complex Person class was causing my problems, I edited the GetOfficers() method to use an anonymous list:
protected void GetOfficers() {
var officers = Personnel.GetOfficers();
var data = from o in officers
select new {
o.Rank,
o.LastName,
o.FirstName,
o.HomePhone,
o.PersonalEmail,
};
//var data = (from o in officers
// select new {
// o.Rank,
// o.LastName,
// o.FirstName,
// o.HomePhone,
// o.PersonalEmail,
// }).OrderBy(o => o.Rank).OrderBy(o => o.LastName);
lvOfficers.DataSource = data;
lvOfficers.DataBind();
}
I was pretty sure that was going to solve my problems at first, so I included the two OrderBy clauses. When it did not work, I commented it out to try again, but I still got no success.
No matter what I seem to try, the page displays with the "Eval" text showing instead of the actual data.
I'm guessing the answer is something simple that I am overlooking because I use this same technique to populate the data in other pages in the same project.
How do I get my data to show up?
You need % at the start like this:-
'<%# Eval("Rank") %>'
you need to add % sign at the start of eval
'<%#Eval("FieldName")%>'
I want to insert the selected item of drop down list into database but my drop down list keep returns the first option . auto post back is false .
codes here :
dropTask() = drop down list where I populate it from database.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dropTask();
}
}
protected void AjaxFileUpload1_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
String pathdirectory = (dropListActivity.SelectedItem.Text+"/");
String filepathImage = (pathdirectory + e.FileName);
EnsureDirectoriesExist(pathdirectory);
AjaxFileUpload1.SaveAs(Server.MapPath(filepathImage));
Session["filepathImage"] = filepathImage;
}
i had checked the value return from drop down list using label :
protected void btnDone_Click(object sender, EventArgs e)
{
if (Session["filepathImage"] != null)
{
string filepathImage = Session["filepathImage"] as string;
Label1.Text = filepathImage;
}
}
the label text show the first option of the drop down list value instead of the choice I have chosen . Please enlighten me on this .
ASPX:
<tr>
<td>
<h2>Upload your Story!</h2>
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
</td>
</tr>
<tr>
<td colspan = "2"></td>
</tr>
<tr>
<td>
<b>Select Activity:</b>
</td>
<td>
<asp:DropDownList ID="dropListActivity" runat="server"
onselectedindexchanged="dropListActivity_SelectedIndexChanged">
</asp:DropDownList>
</td>
</tr>
<tr>
<td colspan = "2"></td>
</tr>
<tr>
<td>
<b>Story Title:</b>
</td>
<td>
<asp:TextBox ID="txtStoryTitle" runat="server"
ontextchanged="txtTitle_TextChanged" AutoPostBack="True"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style1">
<b>Upload your files here:</b><br />
Multiple Images and 1 Audio file only.
</td>
<td class="style1">
<asp:AjaxFileUpload ID="AjaxFileUpload1" runat="server"
onuploadcomplete="AjaxFileUpload1_UploadComplete"
/>
</td>
</tr>
<tr>
<td colspan = "2"></td>
</tr>
<tr>
<td>
<asp:Label ID="Label1" runat="server" ></asp:Label>
</td>
<td>
<asp:Button ID="btnDone" runat="server" Text="Done" onclick="btnDone_Click" />
</td>
</tr>
DropListActivity.SelectedItem.ToString should do the trick. There are a few other things you should keep in mind:
Make sure you are not populating the dropdownlist on a postback.
Selected value will only be available at the sever if the portion of
the page containing the dropdownlist control is posted back.i.e if
you are using an update panel your dropdownlist should be present
within that panel or if you are posting back the entire page then there wont be any problem at all provided you meet the first criteria.
Your event handler dropListActivity_SelectedIndexChanged will
always be fired when a page is posted back and the seleceted index
has changed. The event handler dropListActivity_SelectedIndexChanged will be called after the page_load subroutine is executed.
I assume you need something like:
private void SaveSelected()
{
ViewState["SelectedItem"] = dropListActivity.SelectedItem;
}
which you use on dropListActivity_SelectedIndexChanged and
private void LoadSelected()
{
if (ViewState["SelectedItem"] != null)
dropListActivity.SelectedItem = (ListItem)ViewState["SelectedItem"];
}
which you call after dropTask();
Please, refer to this post's answer
in dropListActivity_SelectedIndexChanged event do like
if(dropListActivity.Items.Count > 0)
{
ViewState["DropDownSelectedValue"] = dropListActivity.Item.SelectedValue;
}
and on Load or databind of drop down list event write
if(ViewState["DropDownSelectedValue"] != null && dropListActivity.Items.Count > 0)
{
dropListActivity.SelectedValue = ViewState["DropDownSelectedValue"].ToString();
}
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();
}
}
}
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.