Unable to bind Header Template with L2S IQueryable list - c#

I have method that is returning IQuerable given below:
internal IQueryable<TradeLeads> GetLeadsByCategory(int categoryId)
{
return
_context.BuySells.Where(bs => bs.CategoryId == categoryId).OrderBy(bs => bs.CreationDate).Select(
bs => new TradeLeads
{
Id = bs.Id,
BuySellTypeId = Convert.ToInt32(bs.BuySellTypeId.ToString()) ,
Description = bs.Description,
Flag = bs.Company.Country1.Flag,
MembershipType = bs.Company.MembershipType,
IsUsingSmsNotifications = bs.Company.IsUsingSMSNotifications,
IsVerified = bs.Company.IsVerified,
ProductImagePath = bs.ProductImagePath,
ProductName = bs.ProductName,
CompanyName = bs.Company.CompanyName,
CompanyId = Convert.ToInt32(bs.CompanyId.ToString()),
PostedDate = bs.CreationDate
});
}
All fields are having values. I am binding BuySellTypeId in the header template of the repeater control. ASPX is given below, which is in Usercontrol.
<HeaderTemplate>
<div class="grdheader">
<div class="hdrText">
<h3 id="h3TypeName">
</h3> <asp:HiddenField runat="server" ID="HidTypeId" Value='<%#Eval("BuySellTypeId") %>'/>
</div>
<div class="hdrMore">
<a href='<%#string.Format("ViewAll.aspx?t={0}",Eval("BuySellTypeId"))%>'>
<img src="cdn/images/more.png" />
View More </a>
</div>
</div>
</HeaderTemplate>
I am binding repeater from its parent page something like this. First I changed the protection level of the repeater from protected to public, so that I can access it from any where, without casting or finding from parent page.
private void BindAllBuyAndSellLeads(int categoryId)
{
var repo = new LeadsRepository();
var list = repo.GetLeadsByCategory(categoryId);
BindGrid(1, Leads1.LeadsGrid, list);
BindGrid(2, Leads2.LeadsGrid, list);
}
private static void BindGrid(int leadTypeId, Repeater gv, IQueryable<Core.Helper.TradeLeads> list)
{
var query = (from p in list
where p.BuySellTypeId == leadTypeId
select p).ToList();
Common.BindGrid(query, gv);
}
here Leads1 and Leads2 are the user control Leads.ascx. That is same usercontrol is placed at two places on page. But i am getting empty while binding. Please help , where and what i am doing wrong.

Binding in a header will never work. Binding is for ItemTemplate only; you can programmably set the value in the header, but realize the repeater is for binding multiple rows of data; there are multiple items, but only one header. Which BuySellTypeId should be used? The first one? The last one? There is no way for the repeater to tell, so you would have to programmably set the value.

Related

Dynamically Access Properties in ASP.NET Razor

I'm trying to access the properties of a class dynamically in ASP.NET Razor when generating an HTML Table. This problem is normally easily solved with reflection, but the #Html.DisplayFor method is giving me issues.
I am attempting to generate an HTML table that has 3 cells per row, with the title of the item in bold as the first line of the cell, and the value of the item in the second line of the cell. The contents of the table should not include cells which are on the 'Excluded Fields' list, and I do not want to have to statically reference each column.
<table class="blpSecurityTable">
<tr>
#{
int _rowCount = 0;
foreach (var property in item.GetType().GetProperties())
{
#if (!Model.ExcludedFields.Contains(#property.Name))
{
dynamic test = #property.GetValue(item);
<td><b>#Html.DisplayFor(m => #property.Name)</b><br />#Html.DisplayFor(m => #test)</td>
_rowCount++;
}
#if (_rowCount % numCols == 0)
{
#:</tr><tr>
}
}
}
</tr>
</table>
I've tried calling #Html.DisplayFor(m => #property.GetValue(item)) but that just creates a runtime error. I can simply call #property.GetValue(item) and the value displays, but this is not ideal because I use display templates to do things like set dates to the ShortDateString format.
I understand that DisplayFor is using reflection to determine the type of the property, and that is why I am trying to use the dynamic variable to facilitate reflection for the method. However, when I run the method, it throws errors indicating the variable is not a generic parameter, and therefore cannot share its attributes. The resulting page has mostly blank values, and some cells filled in with unexpected descriptive information.
I feel like I'm getting close, but I don't know how to proceed. The page won't look right if I don't pass the values into an HTML display method, and I cannot think of any other way to get the type of table I want to be generated. Thoughts?
The issue is solved by creating a Display Template for the Security object, which then allowed me to properly use the #Html.Display Method, because the Model for the Display Template has an entry for the property.
Here is what the page code looks like now:
Display Template
#model Interface.Models.Security
#{int numCols = 3;}
<table class="blpSecurityTable">
<tr>
#{
int _rowCount = 0;
foreach (var property in Model.GetType().GetProperties())
{
#if (!BLPDLModel.ExcludedFields.Contains(#property.Name))
{
<td><b>#Html.DisplayFor(m => #property.Name)</b><br />#Html.Display(property.Name)</td>
_rowCount++;
}
#if (_rowCount % numCols == 0)
{
#:</tr><tr>
}
}
}
</tr>
</table>
Razor Page
#foreach (var item in Model.Security)
{
<div class="blpSecurityItem">
<button type="button" class="collapsible">{button text}</button>
#{
<div class="collapsible-content">
<hr />
#Html.DisplayFor(m => item)
</div>
}
</div>
Replace #Html.DisplayFor(m => #test) with #Html.Display(property.Name)
and your model property for date should have [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")] or anything you like

Display content in Repeater

I must have done so that I can print anything into my Repeater, but it is such that I can not really for it to write the content that I really want to do.
I have written the code like this
forum.aspx
<asp:Repeater ID="RepeaterKommentar" runat="server">
<ItemTemplate>
<div class="kommentarBox">
<%--print content here--%>
</div>
</ItemTemplate>
</asp:Repeater>
forum.aspx.cs
var UsersKommentar = from KommentarA in db.forumkommentars
join BrugereA in db.brugeres on KommentarA.brugerid equals BrugereA.Id
where KommentarA.forumid == getid
orderby KommentarA.Id descending
select new
{
UserName = BrugereA.fornavn + " " + BrugereA.efternavn
};
RepeaterKommentar.DataSource = UsersKommentar;
RepeaterKommentar.DataBind();
The problem, is I'm not entirely sure how to access the object of Enumerable through my data source.
I'm not sure what data exist within your object, but you've bound it to the repeater and called data bind. So all you need to do now is call:
<%# Eval("...") %>
The ... would represent the name of the column, or property.

Sorting a list with asp.net usercontrols by property value

I am populating a div with many usercontrols, right now they are being added in the order that they are being read from the db. The UserControls markup looks like this:
<div class="Content_Thumb">
<div class="Video_pic">
<a href="tutorialname.aspx">
<asp:Label ID="TutInfo" CssClass="CoverLbl_top" runat="server" Text="Label"></asp:Label>
<asp:Label ID="TutInfo2" CssClass="CoverLbl_bottom" runat="server" Text="Description..."></asp:Label>
<asp:Image ID="ThumbPic" CssClass="Thumb_Pic" runat="server" ImageUrl="/Images/Video_Thumb.png" />
</a>
</div>
<div class="Thumb_Info">
<asp:Label ID="Views" CssClass="ViewsLbl" runat="server" Text="680"></asp:Label>
<asp:Label ID="Comments" CssClass="CommentsLbl" runat="server" Text="11"></asp:Label>
<asp:Label ID="Likes" CssClass="LikesLbl" Style="TEXT-ALIGN: right" runat="server" Text="133"></asp:Label>
</div>
<div class="Thumb_Border">
<asp:Image ID="UserPic" CssClass="Thumb_UploaderPic" runat="server" ImageUrl="/Images/Profile_Placeholder.png" />
<a href="google.com">
<asp:Label ID="UserLbl" CssClass="Thumb_UploaderInfo" runat="server" Text="Label"></asp:Label>
</a>
</div>
Then i've got these properties that are bound to the labels (some removed since i dont want to clutter the post).
public string TutorialInfo
{
get;
set;
}
public int TutorialViews
{
get;
set;
}
public override void DataBind()
{
TutInfo.Text = TutorialInfo;
Views.Text = TutorialViews.ToString();
Comments.Text = TutorialComments.ToString();
Likes.Text = TutorialLikes.ToString();
UserLbl.Text = TutorialUploader;
base.DataBind();
}
Now, what I want to do with these controls are to sort them by the property values. (highest number of views loads first etc). I'm currently at the stage where i've added them to a list, and now I'm trying to sort that list using LINQ's OrderBy like I saw on a post here.
List<UserControl> controls = new List<UserControl>();
foreach (var Tutorial in dataconnection.Tutorial)
{
var control = LoadControl("~/WebUserControl1.ascx") as WebUserControl1;
control.TutorialInfo = Tutorial.Title;
control.TutorialComments = (int)Tutorial.Comments;
control.TutorialViews = (int)Tutorial.Views;
control.TutorialLikes = (int)Tutorial.Likes;
control.TutorialUploader = Tutorial.Uploader;
control.DataBind();
//base.OnPreRender(e);
ThumbTest.Controls.Add(control);
controls.Add(control);
var testcount = controls.Count();
control.Visible = false;
}
var SortedList = controls.OrderBy(o => o.TutorialViews).ToList();
However i'm not able to access the properties even though they are public? "o.TutorialViews" is throwing an error. So how can i sort these controls?
I'm Fairly new to programming in general so my apologies if this turns out to be a silly mistake.
TLDR: How do I sort Usercontrols by property value.
Your list is a list of UserControl objects, which is the generic user control provided by ASP.NET:
List<UserControl> controls = new List<UserControl>();
The UserControl object doesn't have a property called TutorialViews, so you can't access that property on that type. However, you're adding custom user controls to the list:
var control = LoadControl("~/WebUserControl1.ascx") as WebUserControl1;
If every item in the list is going to be of type WebUserControl1 then you can declare the list itself with that type:
List<WebUserControl1> controls = new List<WebUserControl1>();
Since WebUserControl1 does define that property, you'll be able to access it.
Another approach might be to cast it when you access it, like this:
controls.OrderBy(o => ((WebUserControl1)o).TutorialViews)
But that's kind of messy and shouldn't be necessary. It's better to use the correct type in the first place.
Essentially, this is a symptom of the statically typed nature of C# (and many other languages). Type B inherits from Type A, so every instance of B is an instance of A. But not every instance of A is an instance of B, so you can't call a B property on an instance of A.
Think of an analogy... You have a list of Shape objects, and you populate it with Circle objects. This works, because Circles are Shapes. But then you try to access the Radius property on an element in that list, and you get an error. This is because it's a list of Shapes and not every shape has a Radius. You'd need to either make it a list of Circles or cast that element to a Circle for the compiler to know that there's a Radius.
For lots of further reading on the subject, take a look at Polymorphism and the Liskov Substitution Principle.

hide multiple <li> list items in code-behind

I have a very huge unordered list items in my masterpage. say it contains 60+ list items. depending on some condition i want hide that list items (hidden items could be 1 to 59 )
My Master File Code Snippet :
<li>Authorization
<ul>
<li><span>Card Request</span></li>
<li><span>Card Issue</span></li>
<li><span>Card Reload</span></li>
<li><span>Close Card</span></li>
<li><span>Card Replacement</span></li>
<li><span>Card Status Change</span></li>
<li><span>Upgrade/DownGrade</span></li>
</ul>
</li>
Condition : -
My DataTable returns values like
cardIssueAuth.aspx
Distributor.aspx
CardStatuschangeAuth.aspx
UpgradeDowngradeAuth.aspx
So i want to hide only those page which came in DataTable
I am aware of ID & runat attribute of <li> & then make it visible : false
But how can i use it efficiently/dynamically ? by using some for loop ...!!
I personally donot like the 'visibility' hack. You could selectively render the 'li' elements on the server-side itself (via code-behind or scriptlets) based on the entries on DataTable.
On the code-behind, you could have a static dictionary that contains all the link details, grouped by sections. Plus the filtering logic:
var sections = new List<Section>()
{
new Section()
{
Header = "Authorization",
SubLinkDetails = new Dictionary<string, string>()
{
{"NewCardGeneration.aspx", "Card Request"},
{"cardIssueAuth.aspx", "Card Issue"},
//.. and so on
}
}
//.. other sections follow
};
//filter subLinkDetails depending on the DataTable entries
sections.ForEach(s => s.SubLinkDetails.RemoveWhere(k => DataTable.Contains(k)));
Here, the Section is a convenience class and RemoveWhere is an extension method on IDictionary:
class Section
{
public string Header { get; set; }
public IDictionary<string,string> SubLinkDetails { get; set; }
}
public static class IDictionaryX
{
public static void RemoveWhere<K,V>(this IDictionary<K,V> dictionary, Predicate<K> condition)
{
IEnumerable<K> keysToRemove = dictionary.Keys.Where(k => condition(k));
foreach (var k in keysToRemove)
{
dictionary.Remove(k);
}
}
}
In your aspx, access the sections and render the ul/li elements:
<%foreach (var section in sections)
{%>
<li><%=section.Header %>
<%foreach (var filteredLink in section.SubLinkDetails)
{%>
<li><span>"<%= filteredLink.Value>"</span></li>
<%}%>
</li>
<%}%>
Provide id to your <li> according to page names.
And then,
You can do this by
if (listItem.selectedItem == 'pagename.aspx')
this.hide.style.Add("display", "none");

How can I make sure that that the number displays correctly on each grid that gets added?

I am using MVC + EF
I have a Feed xml file url that gets updated every 7 minute with items, every time a new item gets added I retrieve all the items to a list variable and then I add these varible to my database table. After that I fill a new list variable which is my ViewModel from the database table. Then I declare the ViewModel inside my view which is a .cshtml file and loop throught all of the objects and display them.
How can I make sure that the newest items get placed on the top and not in the bottom and also the numbers displays in correct order?
This is how I display the items inside my cshtml note that I use a ++number so the newest item needs to be 1 and so on ::
#model Project.Viewmodel.ItemViewModel
#{
int number = 0;
}
<div id="news-container">
#foreach (var item in Model.NewsList.OrderByDescending(n => n.PubDate))
{
<div class="grid">
<div class="number">
<p class="number-data">#(++number)</p>
</div>
<p class="news-title">#(item.Title)</p>
<div class="item-content">
<div class="imgholder">
<img src="#item.Imageurl" />
<p class="news-description">
#(item.Description)
<br />#(item.PubDate) |
Source
</p>
</div>
</div>
</div>
}
</div>
This is how I fill the viewmodel which I use inside the .cshtml file to iterate throught and display the items
private void FillProductToModel(ItemViewModel model, News news)
{
var productViewModel = new NewsViewModel
{
Description = news.Description,
NewsId = news.Id,
Title = news.Title,
link = news.Link,
Imageurl = news.Image,
PubDate = news.Date,
};
model.NewsList.Add(productViewModel);
}
If you check this image thats how it gets displayed with the numbers, thats incorrect.
If you see the arrows thats how it should be, how can I accomplish that?
Any kind of help is appreciated :)
note: When I remove .OrderByDescending, the numbers are correctly on each grid. But I need the .OrderByDescending beacuse i want the latest added item in the top.
Try this:
#model Project.Viewmodel.ItemViewModel
#{
int number = 0;
var NewsItems=Model.NewsList.OrderByDescending(n => n.PubDate).ToList();
}
<div id="news-container">
#foreach (var item in NewsItems)
{
<div class="grid">
<div class="number">
<p class="number-data">#(++number)</p>
</div>
<p class="news-title">#(item.Title)</p>
<div class="item-content">
<div class="imgholder">
<img src="#item.Imageurl" />
<p class="news-description">
#(item.Description)
<br />#(item.PubDate) |
Source
</p>
</div>
</div>
</div>
}
</div>
Looking at your sketch I assume you have float: left or display: inline-block for a grid class. Adding float: right might do the trick.
If that does not help please post CSS you have.
just a quick word..
you are passing NewsViewModel to the view and performing iteration on ItemViewModel ..y?
do u think this may be the cause of the problem..
Regards
You could sort your news list using the CompareTo method:
model.NewsList.Sort((a, b) => b.PubDate.Date.CompareTo(a.PubDate.Date));
Once you have the list sorted correctly, you can simply use CSS to display the news list two items per row. See this fiddle.
The fiddle is a revised one which was provided to me in a similar question I asked before.
Try this one
private void FillProductToModel(ItemViewModel model, News news)
{
var newList = list.OrderByDescending(x => x.News.Date).toList();
var productViewModel = new NewsViewModel
{
Description = newList .Description,
NewsId = newList .Id,
Title = newList .Title,
link = newList .Link,
Imageurl = newList .Image,
PubDate = newList .Date,
};
model.NewsList.Add(productViewModel);

Categories