I have the next structure for a menu item:
class MenuItem
{
public string Path, Title;
}
I want to be able to Iterate an object of MenuItem[], creating a new object of asp:HyperLink on each iteration, and to add it to a <ul> list.
One thing that must happen is that each HyperLink will be inside a <li> tag.
How can I do that?
You can use a repeater. In the aspx:
<asp:Repeater ID="repMenuItems" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><asp:HyperLink ID="lnkMenuItem" runat="server" Text='<%# Eval("Title") %>' NavigateUrl='<%# Eval("Path")%>'/></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
And in the codebehind:
repMenuItems.DataSource = arrMenuItem; // your MenuItem array
repMenuItems.DataBind();
Additionaly you should change your class code for using Public Properties instead of Public Members, like this:
public class MenuItem
{
public string Title {get;set;}
public string Path {get;set;}
}
I recommend you to read more about Properties in .NET, a nice feature for object encapsulation http://msdn.microsoft.com/en-us/library/65zdfbdt(v=vs.71).aspx
Hope this helps you
Related
I have a problem with the repeater asp control.
I have a table on my database called course with columns CourseID, CourseName, CourseLink and another table called module with columns ModuleID, ModuleName. And another table called timetable with columns CourseID and ModuleID.
The way this works is when I click on HyperLink1,the paragraph bellow with the the same course id, it would changes the paragraph's style display from hidden to show (I used JavaScript to complete this function so it's not the problem here).
What I would like to know is, how can I list the ModuleNames That relate to that specif course ID.
I was thinking of using another repeater inside a repeater. However that just complicate things and to be hones really confuses me.
How can I get this to work, don't work about the sql because I am comfortable in creating a select command.
Here is the the ASP.NET forum.
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="DataSource1">
<ItemTemplate>
<p>
<a id="HyperLink1" runat="server" href='<%# Eval("courselink") %>'>
<%# Eval("CourseName") %>
</a> <br />
</p>
<p id='<%# Eval("CourseID") %>' style="display:none">
<%# Eval("ModulName") %>
</p>
<br />
</ItemTemplate>
</asp:Repeater>
Thank you for your time and I look forward to finding out what I can do to solve this problem.
You pretty much will need to use another repeater, the trick (if I remember correctly has I haven't used the legacy ASP.NET Web Forms since 2011) is that you hook into the ItemDataBound event in your code behind for the parent repeater and then use the Event Arguments to get the id that you associate to your child table, get that data, lookup the repeater by id from Repeater (I think it's the sender but there is some way to get at it) and bind the data.
I want to note this is much easier and cleaner with ASP.NET MVC and the use of ASP.NET Web Forms is generally discouraged.
It could be the worst this way
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="DataSource1">
<ItemTemplate>
<p>
<a id="HyperLink1" runat="server" href='<%# Eval("courselink") %>'>
<%# Eval("CourseName") %>
</a> <br />
</p>
<p id='<%# Eval("CourseID") %>' style="display:none">
<%# moduleName(Eval("id").ToString()) %>
</p>
<br />
</ItemTemplate>
public string moduleName(string id)
{
string returnValue = "<ul>";
using (SqlConnection con = new SqlConnection(DB))
{
using (SqlCommand com = new SqlCommand("SELECT * FROM module WHERE id = #id", con))
{
com.Parameters.AddWithValue("#id", id);
if (con.State == System.Data.ConnectionState.Closed)
{
con.Open();
using (SqlDataReader dr = com.ExecuteReader())
{
while (dr.Read())
{
returnValue += "<li>"+ dr["modulename"].ToString()+"</li>";
}
}
con.Close();
}
}
}
returnValue += "</ul>";
return returnValue;
}
The best solution would be to create a strongly typed model for your presentation and don't use Eval, you would get something like this in your webform:
<asp:Repeater runat="server" DataSourceID="<%# Model %>">
<ItemTemplate>
<p>
<%# ((Course)Container.DataItem).Name %>
</p>
<p id='<%# ((Course)Container.DataItem).ID %>' style="display:none">
<asp:Repeater runat="server" DataSource="<%# ((Course)Container.DataItem).Modules %>">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# ((Module)Container.DataItem).Name %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</p>
</ItemTemplate>
Then in your code behind create the following property:
public List<Course> Model
{
get
{
List<Course> courses = new List<Course>();
// Some example data, in your situation you should instantiate the classes based on the data from the database.
Course exampleCourse = new Course();
exampleCourse.ID = 1;
exampleCourse.Name = "Example course";
// Create example module 1
Module exampleModule1 = new Module();
exampleModule1.ID = 10;
exampleModule1.Name = "Example Module 1";
// Create example module 2
Module exampleModule2 = new Module();
exampleModule2.ID = 11;
exampleModule2.Name = "Example Module 2";
// add modules to the course
exampleCourse.Modules.Add(exampleModule1);
exampleCourse.Modules.Add(exampleModule2);
// add course to the courses
courses.Add(exampleCourse);
return courses;
}
}
Classes needed:
public class Course
{
public int ID { get; set; }
public string Link { get; set; }
public string Name { get; set; }
public List<Module> Modules { get; set; }
public Course()
{
this.Modules = new List<Module>();
}
}
public class Module
{
public int ID { get; set; }
public string Name { get; set; }
}
Last, in your page load, don't forget to databind:
protected void Page_Load(object sender, EventArgs e)
{
this.DataBind();
}
Ok I have a many to many relationship like this:
Walk = {WalkID, title, ...., (Navigation Properties) Features}
Feature = {FeatureID, featureName, description, (Navigation Properties) DogWalks}
I do of course have a junction table, but EF assumes this thus it is not shown in my edmx diagram:
WalkFeatures = {WalkID, FeatureID} //junction, both FK
So using LINQ with EF, I am now trying to grab the features for the Walk at WalkID=xx.
This is my formview:
<asp:FormView ID="FormView1" runat="server" ItemType="Walks.DAL.Walk" SelectMethod="FormView1_GetItem">
<ItemTemplate>
<h1><%# Item.Title %></h1>
...
</ItemTemplate>
</asp:FormView
<asp:Label ID="lbFeatures" runat="server" Text="Label"></asp:Label>
And selectMethod:
public Walks.DAL.Walk FormView1_GetItem([QueryString("WalkID")] int? WalkID)
{
using (WalkContext db = new WalkContext())
{
var walk = (from n in db.Walks.Include("Features")
where n.WalkID == WalkID
select n).SingleOrDefault();
foreach(var f in walk.Features){
lbFeatures.Text += f.FeatureName + "<br/>";
}
return walk;
}
}
The code runs fine, but is there a way that I can display the Walk.Features directly inside the <ItemTemplate> of the formview rather than using a label and a loop? Can the attribute be directly binded like the other properties in the .aspx page?
I have also used this new feature not that extensively but just gave it a try for this particular scenario and this is what I have:-
Simply return walk from FormView1_GetItem method and don't manipulate your label control there. Now, you can use a Repeater control to display the lbFeatures control (since it is going to repeat dynamically) like this:-
<ItemTemplate>
<h1><%# Item.Title %></h1>
<asp:Repeater ID="lbFeatures" runat="server" DataSource='<%# Item.Features%>'>
<ItemTemplate>
<asp:Label ID="lblTest" runat="server"
Text='<%# Eval("FeatureName") %>'></asp:Label>
<br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
As you can see I am able to assign the datasouce of repater control as Item.Features, then use the conventional approach to bind the label. This looks clean and simple :)
How can i use it in Repeater ItemTemplate ?
foreach(string tag in Eval("etiketler"))
{
Response.Write("<a href='#'>"+tag+"</a");
}
there is no way to do it in this format. you should send Dataitem to a static method and then you should return string that contains your markup..
public static string GetMarkup(object dataItem)
{
var tags = DataBinder.Eval(dataItem, "etiketler"); // depend on etiketler type
StringBuilder sb = new StringBuilder();
foreach(string tag in tags)
{
sb.Append("<a href='#'>"+tag+"</a");
}
return sb.ToString();
}
use this method like this:
<%# GetMarkup(Container.DataItem) %>
<%# is not made to use foreach with it, neither if or other language keywords. It's mainly done to databinding.
But you can :
Do it in codebehind with the _ItemDataBound event of the repeater (hugely recommanded for complex processings/formatting).
See http://msdn.microsoft.com/fr-fr/library/system.web.ui.webcontrols.repeater.itemdatabound%28v=vs.110%29.aspx
Call a method of the page which takes in parameter the DataItem and creates the data you want. See How do you pass a Container.DataItem as a parameter? for example
Hope this helps
You can also use nested repeaters in ASP.NET
<asp:Repeater runat="server" ID="rpt1">
<ItemTemplate>
<asp:Repeater runat="server" ID ="rpt2" DataSource='<%# Eval("etiketler") %>'>
<ItemTemplate>
<%# Eval("tag") %>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
My web project uses LINQ To SQL to access the data and a repeater control to display it.
To my knowledge, the repeater doesn't have a paging system built into it like a GridView does, so I thought I'd opt for an infinite scroll.
I found this jquery plugin that seemed to work initially although after a few tests, I found that it wasn't "hiding" items anymore.
The project uses a "behind-the-scenes" class where the data access is done, clearing up the page's partial class to handle how the data is displayed:
// App_Code/netGuestData.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using netguestModel;
public class netguestData
{
private netguestEntities ne = new netguestEntities();
public netguestData()
{
//
// TODO: Add constructor logic here
//
}
public IEnumerable<post> GetPosts()
{
var posts = from p in ne.posts
select p;
return posts;
}
}
// ~/Default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
loadGuestbook();
}
}
private void loadGuestbook()
{
netguestData nd = new netguestData();
rptGuestbook.DataSource = nd.GetPosts();
rptGuestbook.DataBind();
}
}
Here's the markup...
<asp:Repeater runat="server" ID="rptGuestbook" OnItemCommand="rptGuestbook_ItemCommand"
OnItemDataBound="rptGuestbook_ItemDataBound">
<ItemTemplate>
<div runat="server" id="divPost" class="post">
<div runat="server" id="divAuthor" class="author">
<asp:Panel runat="server" ID="pnlAdmin" CssClass="delete-button" Visible="false">
<asp:Button runat="server" ID="btnDeletePost" CssClass="button" Text="Delete Post"
CommandName="DeletePost" CommandArgument='<%# Eval("postid") %>' />
<asp:Label runat="server" ID="lblShowEmail" Text='<%# Eval("showemail") %>' CssClass="hidden"></asp:Label>
</asp:Panel>
<ul>
<li><span>Posted By: </span>
<%# Eval("postauthor") %><br />
<li>
<asp:HyperLink runat="server" ID="lnkWeb" ImageUrl="~/Images/webicon.png" NavigateUrl='<%# Eval("webaddress") %>'></asp:HyperLink></li>
<li>
<asp:HyperLink runat="server" ID="lnkEmail" ImageUrl="~/Images/emailicon.png" NavigateUrl='mailto: <%# DataBinder.Eval(Container.DataItem, "emailaddress" %>'></asp:HyperLink></li>
</ul>
</div>
<div runat="server" id="divMessage" class="post-message">
<div class="post-date"><span>Posted On:</span> <%# Eval("postdate") %></div>
<%# Eval("postmessage") %></div>
<div class="scroll"></div>
</div>
</ItemTemplate>
</asp:Repeater>
It's all pretty straightforward. To achieve infinite scroll with the repeater, I found this article on dotnetcurry but this just does everything in the _Default partial class which doesn't suit me at all.
I've been trying to figure out how to tweak this example to fit my situation, but so far, I'm coming up empty.
If anyone can help me to make infinite scrolling work on my project - even if you just explain the concept of what I have to do - I'd be very grateful.
Thanks in advance!
Okay so I asked in a group on facebook and someone there suggested lazy loading.
Here's a question I asked a little while ago that has all the details.
NOTE:
After changing my code to take the answer to the question into account, I've noticed that this doesn't add the 2nd/3rd/4th/etc set of 10 rows to the existing set as I had expected.
I am attempting to list a group of Associations, within each association is a 'widget' that is assigned to the association. The list will include the Association name and any widget assigned to it. The catch is that the inner widget list needs to be sorted by DisplaySequence.
EDMX Model Below:
Simplified Repeater Mark-Up
<asp:Repeater ID="rptAssociations" runat="server">
<ItemTemplate>
<div data-type="assn" id="<%# ((Association)Container.DataItem).AssociationID %>">
<h3 style="margin-top:15px;"><%# ((Association)Container.DataItem).Acronym %> - <%# ((Association)Container.DataItem).Name %></h3>
<asp:Repeater runat="server" ID="rptWidgets" DataSource="<%# ((Association)Container.DataItem).AssociationWidgets %>" >
<HeaderTemplate>
<ul class="WidgetList">
</HeaderTemplate>
<ItemTemplate>
<li id="<%# ((AssociationWidget)Container.DataItem).DisplaySequence %>"><%# ((AssociationWidget)Container.DataItem).Widget.Name %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
Current Query
var associations = (from a in
context.Associations.Include("AssociationWidgets")
.Include("AssociationWidgets.Widget")
orderby a.Acronym
select a).ToList();
rptAssociations.DataSource = associations;
rptAssociations.DataBind();
I am currently able to get the data that I'm looking for with the setup that I have now. I am looking for the most efficient approach to getting this same data, however, having the Widgets listed in the correct display order.
Is there a different approach to the linq query I should take?
I would approach this like this (untested):
var associations =
context.Associations.Select( a =>
new {
//... specific properties you need
AssociationId = a.AssociationId,
Name = a.Name,
... etc
Widgets = a.AssociateWidgets.OrderBy(aw => aw.DisplaySequence)
.Select(aw => aw.Widget)
}
);
Here you'll get a collection of anonymous types. You can use a concrete type such as
public class AssociationInfo
{
public string Name {get;set;}
...
public IEnumerable<Widget> Widgets{ get;set; }
}
if necessary by replacing 'new {' with 'new AssociationInfo {'