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")%>'
Related
as Title
in my code,there are 2 buttons : "btnA" and "btnB"
When I press btnA , I expect that the ListView will show "EditItemTemplate_Edit" and do not show "EditItemTempPlate_Reset"
btnB is similar to btnA
I already added 2 EditItemTemplates in ListView like this :
<EditItemTemplate>
<tr class="EditItemTemplate" style="text-align: left;" id="EditItemTemplate_Eidt">
<td><asp:Label ID="Label_Factory" runat="server" Text='<%# Eval("test1") %>' /></td>
</tr>
<tr class="EditItemTemplate" style="text-align: left;" id="EditItemTemplate_Reset">
<td><asp:Label ID="Label3" runat="server" Text='<%# Eval("test2") %>' /></td>
</tr>
</EditItemTemplate>
I have already tried using script to set "display" -> "none" but it was not work
plz teach me how to make this work
thanks very much ~"~
I actually suggest in these cases to not even bother with the templates.
You can actually use less markup, less code, and less messy UI for the user.
Why not just let them tab around - make as many changes as they want - almost like a Excel sheet.
then have ONE save button - and on un-do button.
That way:
They just edit - not all this song and dance to hit edit + save buttons
So less UI, less code, and you can just tab around on ANY row - just edit.
Much less code.
So, say we have this markup for the listview.
<style> input {border:none}</style>
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >
<ItemTemplate>
<tr style="">
<td><asp:TextBox ID="txtFirst" runat="server" Text='<%# Eval("Firstname") %>' /></td>
<td><asp:TextBox ID="txtLast" runat="server" Text='<%# Eval("LastName") %>' /></td>
<td><asp:TextBox ID="txtCity" runat="server" Text='<%# Eval("City") %>' /></td>
<td><asp:CheckBox ID="Active" runat="server" Checked='<%# Eval("Active") %>' /></td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" class="table table-hover">
<tr runat="server" style="">
<th runat="server">Firstname</th>
<th runat="server">LastName</th>
<th runat="server">City</th>
<th runat="server">Active</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
<asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn-primary" OnClick="cmdSave_Click1" />
<asp:Button ID="cmdAdd" runat="server" Text="Add Row" CssClass="btn-primary" style="margin-left:20px" OnClick="cmdAdd_Click1"/>
<br />
Note how MUCH LESS markup we have.
The code to load this lv looks like this:
private DataTable rstPeople = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadGrid();
ViewState["MyTable"] = rstPeople;
Session["test"] = "hello";
}
else
rstPeople = (DataTable)ViewState["MyTable"];
}
public void LoadGrid()
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from People",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
rstPeople.Load(cmdSQL.ExecuteReader());
ListView1.DataSource = rstPeople;
ListView1.DataBind();
}
}
So we now have this:
So, you are now free to edit - even tab around almost like a Excel sheet. SUPER easy to edit the data - no special buttons to edit/save each row.
Very nice for the user - no huge UI and clicking and messing around to edit.
And the save button code, again REALLY simple since we send the WHOLE grid edits back to the database in one simple edit!!!
(and ONE update operation for the WHOLE grid!!!).
Save button code:
protected void cmdSave_Click1(object sender, EventArgs e)
{
// pull grid rows back to table.
foreach (ListViewItem rRow in ListView1.Items)
{
int RecordPtr = rRow.DataItemIndex;
DataRow OneDataRow;
OneDataRow = rstPeople.Rows[RecordPtr];
OneDataRow["FirstName"] = ((TextBox)rRow.FindControl("txtFirst")).Text;
OneDataRow["LastName"] = ((TextBox)rRow.FindControl("txtLast")).Text;
OneDataRow["City"] = ((TextBox)rRow.FindControl("txtCity")).Text;
OneDataRow["Active"] = ((CheckBox)rRow.FindControl("Active")).Checked;
}
// now send table back to database with updates
string strSQL = "SELECT ID, FirstName, LastName, City, Active from People WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstPeople);
}
}
So the trick? We persist the data table.
Then to save, you move grid back to data table, and then send the table BACK to the database in one simple update.
And the code to add a new row to the grid is ALSO very easy, we don't have to hit the database, but just add to the table, and then re-bind to the grid.
This code:
protected void cmdAdd_Click1(object sender, EventArgs e)
{
// add a new row to the grid
DataRow OneRow = rstPeople.Rows.Add();
ListView1.DataSource = rstPeople;
ListView1.DataBind();
}
So, notice how we save world poverty, save buckets of code, save buckets of mark-up, and we save buckets of messy UI in which the user has to hit edit/save over and over JUST to edit a few rows.
So, save code, save money, same markup, save messy user interface, provide a MUCH better and seamless user experience.
What more could you want?
Note how we defined the data table at the web page class level - by persisting that data table, then we get all of the wonderful and easy to use benefits above - including MUCH less code, much less markup, and much less user interaction required to edit a few simple rows of data.
And we ONLY send ONE update back to the database to save all rows - all of the dirty work here is thus done by .net for you, and you even wind up with not only MUCH less code, but we hit the database MUCH less for the update.
I did not add a un-do-edits button, but all it would do is call loadGrid again, and that would just re-load the data gain - and thus un-do any of our edits.
(so a un-do button would be a good idea here.)
I am trying to populate an html table with rows based on what a c# function returns on a button click.
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Populate" /></div><br>
<table id ="randtable" class="tablex">
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
<th>Col4</th>
</tr>
</table>
and my Button1_Click function looks like this:
protected void Button1_Click(object sender, EventArgs e)
{
List<Entity> x = someFunction();
//I want to have each row in the table represent each entity. Assume each entity has 4 attributes which would go in Col1,Col2,Col3,Col4 in the table.
}
Any idea how to do this? The reason I'm sticking with an html table instead of an asp control table is to keep the css of the html table, unless there's a way to make the asp table look appealing as well.
Put your table inside a ListView Control:
<asp:ListView runat=server id="lvResults">
<LayoutTemplate>
<table id ="randtable" class="tablex">
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
<th>Col4</th>
</tr>
<asp:PlaceHolder id="itemPlaceholder" runat="server"></asp:PlaceHolder>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%# Eval(Container.DataItem, "col1") %></td>
<td><%# Eval(Container.DataItem, "col2") %></td>
<td><%# Eval(Container.DataItem, "col3") %></td>
</tr>
</ItemTemplate>
</asp:ListView>
Then put the following in your code behind:
protected void Button1_Click(object sender, EventArgs e)
{
List<Entity> x = someFunction();
lvResults.DataSource = x;
lvResults.DataBind()
}
If you specifically want to do it on html table then you can use runat="server" on your table's tbody element then populate your table's rows inside a loop.
your table like this:
<table id ="randtable" class="tablex">
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
</tr>
</thead>
<tbody id="mybody" runat="server">
//your dynamic rows from code behind
</tbody>
</table>
and your class should have something like this:
protected void Button1_Click(object sender, EventArgs e) {
List<Entity> x = someFunction();
foreach (var entity in x)
{
mybody.InnerHtml += string.Format("<tr><td>{0}</td><td>{1}</td></tr>",
entity.value1, entity.value2);
}
}
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 list view which retrieves the data from sql data source. I am trying to make two buttons(Yes and No) and a label outside the list view visible only if the list view is not empty. The process is: a person enter the information into text boxes and click the button retrieve, if the entered data exists in the database, the list view shows certain information.
I have the following code:
protected void btnExistingRetrive_Click(object sender, EventArgs e)
{
if (lstExisting.Items.Count>0 )
{
lblIsITYou.Visible = true;
btnYes.Visible = true;
btnNo.Visible = true;
}
}
By default buttons and the label are not visible.
The problem is when i click on retrieve button it shows me the list view with the information but buttons a the label are still not visible. They became visible only when i double click the retrieve button. Please tell me what is my mistake?
Thank you
Use the ListView EmptyDataTemplate
<asp:ListView ID="ContactsListView"
DataSourceID="ContactsDataSource"
runat="server">
<LayoutTemplate>
<table runat="server" id="tblProducts">
<tr runat="server" id="itemPlaceholder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr runat="server">
<td>
<asp:Label ID="FirstNameLabel" runat="Server" Text='<%#Eval("FirstName") %>' />
</td>
<td>
<asp:Label ID="LastNameLabel" runat="Server" Text='<%#Eval("LastName") %>' />
</td>
</tr>
</ItemTemplate>
<EmptyDataTemplate>
<table class="emptyTable" cellpadding="5" cellspacing="5">
<tr>
<td>
<asp:Image ID="NoDataImage"
ImageUrl="~/Images/NoDataImage.jpg"
runat="server"/>
</td>
<td>
No records available.
</td>
</tr>
</table>
</EmptyDataTemplate>
</asp:ListView>
do you bind listview before checking the items count?
Do this on postback instead of in the event.
In your Page_Load do something like this:
protected void Page_Load(object sender, EventArgs e)
{
bool visible = (lstExisting.Items.Count > 0); // assuming it's never null
lblIsITYou.Visible = visible;
btnYes.Visible = visible;
btnNo.Visible = visible;
}
If the above creates complications then do as I said first with postback:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
bool visible = (lstExisting.Items.Count > 0); // assuming it's never null
lblIsITYou.Visible = visible;
btnYes.Visible = visible;
btnNo.Visible = visible;
}
}
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.