Sort Inner Repeater with LINQ query - c#

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 {'

Related

How to display a Navigation Property of a table inside a Data control like a FormView?

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 to use ul and li in code behind c#

I am trying to fill li and ul of an HTML file using my database.
single category representing multiple items in database.
I have taken the li items in a string, I am replacing [food] with CATEGORY name and [itemTemplate] with ITEMS. The issue in my code is the category name is repeating
Every time as new item display. I have to show category name once and add all related items within that category.
String liTemplate = "<li><h4 class='menu-title-section'> <h4 class='menu-title-section'><a href='#appetizers'>[food]</a></h4>[itemTemplate]</li>";
String itemTemplate = "SOME ITEM TEMPLETE";
DataTable dt = dm.GetData("spTestMenu")
StringBuilder sb = new StringBuilder();
sb.Append("<ul class='our-menu'>");
String liTemplateWorkingCopy = String.Empty, itemTemplateWorkingCopy = String.Empty
foreach (DataRow level1DataRow in dt.Rows)
{
liTemplateWorkingCopy = liTemplate;
itemTemplateWorkingCopy = itemTemplate;
SubCategoryName = level1DataRow["MealSubCatName"].ToString();
if (!previusSubCat.Equals(SubCategoryName))
{
liTemplateWorkingCopy = liTemplateWorkingCopy.Replace("[food]", level1DataRow["MealSubCatName"].ToString());
previusSubCat = SubCategoryName;
}
itemTemplateWorkingCopy = itemTemplateWorkingCopy.Replace("[foodtitle]", level1DataRow["itemName"].ToString());
itemTemplateWorkingCopy = itemTemplateWorkingCopy.Replace("[imgsrc]", level1DataRow["imageURL"].ToString());
itemTemplateWorkingCopy = itemTemplateWorkingCopy.Replace("[price]", level1DataRow["Price"].ToString());
liTemplateWorkingCopy = liTemplateWorkingCopy.Replace("[itemTemplate]", itemTemplateWorkingCopy);
sb.Append(liTemplateWorkingCopy);
foodMenu.Text = sb.ToString();
}
You can set runat="server" for <li> or <ul>..
<li class="abc" runat="server" id="first"></li>
I would suggest using a ListView control for this. This way you can maintain the HTML outside of your code; it's cleaner that way and much more elegant.
Group your rows by the 'MealSubCatName' column, and use LINQ to create an anonymous object:
C#
var grouped = dt.AsEnumerable().GroupBy(c => c["MealSubCatName"].ToString())
.Select(g => new
{
category = g.FirstOrDefault()["MealSubCatName"].ToString(),
items = g.Select(r => new {
title = r["itemName"].ToString(),
image = r["imageURL"].ToString()
})
});
lvFood.DataSource = grouped;
lvFood.DataBind();
ASPX
<asp:ListView ID="lvFood" runat="server">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server" ID="groupPlaceholder" />
</ul>
</LayoutTemplate>
<GroupTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</GroupTemplate>
<ItemTemplate>
<li>
<h4 class="menu-title-section">
<%# Eval("category") %>
</h4>
</li>
<asp:Repeater ID="rpt" runat="server" DataSource='<%# Eval("items") %>'>
<ItemTemplate>
<img src="<%# Eval("image")%>" alt="<%# Eval("title")%>" />
<strong><%# Eval("title")%></strong><br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:ListView>
Add a div with runat server and assign a Id to that div and do something like this I did this trick here www.journeycook.com Check menu of this website.
Suppose you have a div with id link and runat server in ul tag
<ul>
<div runat="server" id="link">
</div>
</ul>
Now add c# code for fetch data using SqlDataReader class and using while loop do something like this
link.innerhtml+="<li>dr["yourcolumn"].ToString()</li>";
I hope it will give you some help

ASP.NET wrap an asp:HyperLink in <li>'s, from server-side

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

Populating a listbox control in asp.net

I have a code block that returns a list of employee object.
The resultset contains more than one employee record. One of the elements, is EmployeeID.
I need to populate listview (lstDepartment) with only the EmployeeID. How can I do that?
lstDepartment.DataSource = oCorp.GetEmployeeList(emp);
lstDepartment.DataBind()
You have to also specify this:
lstDepartment.DataSource = oCorp.GetEmployeeList(emp);
lstDepartment.DataTextField = "EmployeeID";
lstDepartment.DataValueField = "EmployeeID";
lstDepartment.DataBind()
One way would be to use an anonymous type:
lstDepartment.DataSource = oCorp.GetEmployeeList(emp)
.Select(emp => new { emp.EmployeeID });
lstDepartment.DataBind();
Edit: But you also could select all columns but diplay only one. A ListView is not a ListBox or DropDownList. Only what you use will be displayed. So if you're ItemTemplate looks like:
<ItemTemplate>
<tr runat="server">
<td>
<asp:Label ID="LblEmployeeID" runat="server" Text='<%# Eval("EmployeeID") %>' />
</td>
</tr>
... only the EmployeeID is displayed, no matter whatelse is in your DataSource.
You may mention what to display in your ItemTemplate of ListView
<asp:ListView ID="lstDepartment" runat="server">
<ItemTemplate>
<p> <%#Eval("EmployeeID") %> </p>
</ItemTemplate>
</asp:ListView>

JOIN with LinqtoSql, only select TOP(x) on joined table?

I've had a look around on StackOverlow but haven't been able to find a definitive answer on this.
Below I have a code snippet of what I currently have, and I will explain what I am trying to achieve.
Table<Gallery> galleries = pdc.GetTable<Gallery>();
Table<GalleryImage> images = pdc.GetTable<GalleryImage>();
Table<Comment> comments = pdc.GetTable<Comment>();
var query = from gallery in galleries
join image in images on gallery.id equals image.galleryid into joinedimages
join comment in comments on gallery.id equals comment.galleryid into joinedcomments
select gallery;
gallst.DataSource = query;
gallst.DataBind();
From the above I then have the following repeater:
<asp:Repeater ID="gallst" runat="server" EnableViewState="false">
<HeaderTemplate>
<div id="gallery">
</HeaderTemplate>
<ItemTemplate>
<div class="item">
<h2><%# DataBinder.Eval(Container.DataItem, "name") %> # <%# DataBinder.Eval(Container.DataItem, "wheretaken") %></h2>
<ul class="images">
<asp:Repeater ID="galimgs" runat="server" EnableViewState="false" DataSource='<%# Eval("GalleryImages") %>'>
<ItemTemplate>
<li><img src="<%# DataBinder.Eval(Container.DataItem, "image") %>_thumb.jpg" /></li>
</ItemTemplate>
</asp:Repeater>
</ul>
<div class="comments">
<asp:Repeater ID="galcomments" runat="server" EnableViewState="false" DataSource='<%# Eval("Comments") %>'>
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# GetUserName(new Guid(Eval("userid").ToString())) %> said: <%#DataBinder.Eval(Container.DataItem, "comment1") %> (<%# DataBinder.Eval(Container.DataItem, "date", "{0:dddd MM, yyyy hh:mm tt}") %>)</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<uc:makecomment ID="mcomment" runat="server" PhotoID='<%# DataBinder.Eval(Container.DataItem, "id") %>'></uc:makecomment>
</div>
</div>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
What I want to do (ideally) is to only take the first 3 comments for each gallery.
I've tried the following LINQ Query with no luck:
var query = from gallery in galleries
join image in images on gallery.id equals image.galleryid into joinedimages
join comment in comments.Take(3) on gallery.id equals comment.galleryid into joinedcomments
select gallery;
Does anyone have any suggestions on how I can achieve this?
This looks like it might be the tweak you need. It's from a very helpful LINQ sample site.
This sample prints the customer ID, order ID, and order date for the first three orders from customers in Washington. The sample uses Take to limit the sequence generated by the query expression to the first three of the orders.
public void Linq21() {
List<Customer> customers = GetCustomerList();
var first3WAOrders = (
from c in customers
from o in c.Orders
where c.Region == "WA"
select new {c.CustomerID, o.OrderID, o.OrderDate} )
.Take(3);
Console.WriteLine("First 3 orders in WA:");
foreach (var order in first3WAOrders) {
ObjectDumper.Write(order);
}
}
Result
First 3 orders in WA:
CustomerID=LAZYK OrderID=10482 OrderDate=3/21/1997
CustomerID=LAZYK OrderID=10545 OrderDate=5/22/1997
CustomerID=TRAIH OrderID=10574 OrderDate=6/19/1997
I managed to get it to work with:
Table<Gallery> galleries = pdc.GetTable<Gallery>();
Table<GalleryImage> images = pdc.GetTable<GalleryImage>();
Table<Comment> comments = pdc.GetTable<Comment>();
var query = from gallery in galleries
join image in images on gallery.id equals image.galleryid into joinedimages
join comment in comments on gallery.id equals comment.galleryid into joinedcomments
select new
{
name = gallery.name,
wheretaken = gallery.wheretaken,
id = gallery.id,
GalleryImages = joinedimages,
Comments = joinedcomments.Take(3)
};
gallst.DataSource = query;
gallst.DataBind();
With the take taken place on the select. Thanks for your help everyone. Any suggestions on how to write this "better" would be appreciated.

Categories