In my code behind I have a public IEnumerable<dynamic> AllTransactions{ get; set; } that is composed of {Transaction, String} (created via linq-to-sql as a new anonymous object) where Transaction is a custom class I have created.
In my aspx page I would like to do the following
<% foreach (dynamic trans in AllTransactions) { %>
<span><%= trans.transaction.Amount %></span>
<% } %>
In my code behind I can refer to trans.transaction.Amount inside a foreach but I don't seem to have any luck on aspx pages. I get an exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'transaction'
At the same time, if I have the debugger running I can look at 'trans' and I see it has a Transaction object inside it called 'transaction' and it has my string as well. Further, the 'transaction' object inside it contains a value for Amount. It seems that Microsoft is somewhere converting my dynamic to an object.
One other test I did was spit out what the type of trans is with GetType() and got this:
<>f__AnonymousTypef`2[ProjectName.Packages.Investment.Business.Transaction,System.String]
This is not a regular 'object', so I'm not sure what the type of this is. Any ideas as to why my foreach doesn't work and what I can do differently?
Try binding your data to a repeater control. It was designed to output html for items in lists, and will help you separate your design from your logic, which is generally considered a much better practice than trying to dynamically generate html in script.
Can you try this as below?
<% foreach (dynamic trans in AllTransactions) { %>
<span><%= trans.Amount %></span>
<% } %>
Or can you check whether the definition of the custom class Transaction includes a member variable whose name is "Transaction"?
Related
i have a list view in my pages and i want to display some statistics, my Restaurant class has a Reservations property public List<Reservation> Reservations { get; private set; }, in my ListView, i would like to display number of reservations, but without making a new property like "ReservationsCount", nothing like this <%#Eval("Reservations")%>.Count doesn´t work
<td id="Td10" runat="server">
<%#Eval("Reservations")%>
</td>
Result of this <%#Eval("Reservations")%> is in the aspx page considered object, not a list of Restaurants, i don´t really know why, i am just beggining with asp.net so please help, maybe the solution is ridiculously easy:)
Try applying the count() directly after the Eval():
<%# ((List<Reservation>)Eval("Reservations")).Count() %>
As far as I know you would need to reference System.Linq for this to work. Without Linq you could try using the Count property of List<T>:
<%# ((List<Reservation>)Eval("Reservations")).Count %>
i have written the following code in my view and i have to print value of variables of my forloop variables company in my view how can i do this
<table><tr>
<td>
<%
var ResDet1 = (from r in db.Res_Exp
where r.Resume.ResumeID == 191
select new{r.ResExpID,r.Company}).ToList();
string company;
int exprinceid;
if (ResDet1 != null)
{
foreach (var rc in ResDet1)
{
exprinceid = rc.ResExpID;
company = rc.Company;
}
}
%>
</td></tr></table>
i believe following code
var ResDet1 = (from r in db.Res_Exp
where r.Resume.ResumeID == 191
select new{r.ResExpID,r.Company}).ToList();
belongs to repository and
string company;
int exprinceid;
should be included in your model. Only foreach should appear in the view. In your controller you should call method of your repository and wrap everything in a view model and pass it to the view. In view you should only iterate and render values (either in display mode or in edit mode). Look at this question for how to implement repository pattern in asp.net mvc
Answer - as requested.
Why use a loop? Make use of MVC's templating.
Create a display template called MyModel, where MyModel is whatever type ResDet1 is:
Shared\DisplayTemplates\MyModel.cshtml
<tr>
<td><% Html.DisplayFor(model => model.ResExpID) %></td>
<td><% Html.DisplayFor(model => model.Company) %></td>
</tr>
Then your main View simply becomes this:
<table>
<% Html.DisplayForModel() %>
</table>
How does that work? Well, your View should be strongly-typed to an IEnumerable<ResDet>, which as #Muhammad mention's, should be fetched via a Repository.
Your action should be something like this:
[HttpGet]
public ActionResult Index()
{
var results = _repository.ResDets();
return View(results);
}
Ideally, you should be using the Repository pattern to talk to the model, use AutoMapper to flatten the model into a ViewModel, and use interface-driven Dependency Injection to handle the dependencies (e.g _repository).
But if that's too much for you, at the very least, put the data access code in the action method, never, i repeat, never in the View.
Now isn't that nicer?
Controller has 2 lines of code - one to retrieve the model, another to call the View. Textbook stuff.
View is dumb. It renders out what it needs to, and is focused on presentation only.
The foreach loop is avoided, as MVC will do an implicit foreach loop, since it sees the model is of IEnumerable<Something>, so it looks for a template matching that Something, and finds your custom template.
Try not to forget the principles of MVC. If your mixing code and markup in your View, you've already lost and may as well be coding in classic ASP.
Usually you'd do something like:
<% foreach (var someVar in someCollection)
{ %>
<%: someVar %>
<% } %>
To print in a loop.
Well, presently, your foreach loop is running entirely within your view engine's code block. The code is running, and those variables are being reassigned a number of times, but you're never telling the C# to write any HTML. I don't write in ASPX, I write in the Razor, so I don't know much for how to escape in and out of C# mode, but I think it'd be something like this:
<table>
<%
var ResDet1 = (from r in db.Res_Exp
where r.Resume.ResumeID == 191
select new{r.ResExpID,r.Company}).ToList();
string company;
int exprinceid;
if (ResDet1 != null)
{
foreach (var rc in ResDet1)
{ %>
<tr>
<td><% rc.ResExpID; %></td>
<td><% company = rc.Company; %></td>
</tr>
<% }
}
%>
</table>
EDIT: To be specific, the point is that you want to leave the code to write HTML to the page, and return to finish the code block. As I understand it, MVC is consistent with this principal in both rendering engines.
I think it's obvious that the framework wants use to keep the HTML in the aspx documents, and all code in the code behind to achieve a clean level of separation.
So what do we do when the GridView isn't good enough?
Should I:
Use a repeater control to keep HTML in the presentation layer, but be forced to mix business logic in with the HTML
Or should I mix HTML in with my code behind layer in the form of a StringBuilder?
Let's pretend that you said use the Repeater control.
Typically to return a product description I would do this:
<%# DataBinder.Eval(Container.DataItem, "desc") %>
But then I run into the issue of when I want to only return 150 characters of the desc in case it's too long. If my datasource was LINQ to SQL I could just create a new string:
string s = q.desc.lengh > 150 ? q.desc.SubString(0,150) + "..." : q.desc;
How would I do the same inside the repeater within the aspx document if it is preferred I use the repeater?
I would use a Repeater, making html in code behind is messy and hard to maintain.
No reason why you can't use helper methods in the code behind (or elsewhere) to do this
<%# SomeMethod(Eval("desc")) %>
Or on the property of the class you are repeating, have an alternative version with a getter
public class SomeItem
{
public string Desc { get; set; }
public string DescSummary
{
get
{
return Desc.Length > 150 ? string.Format("{0}...", Desc.Substring(0, 150)) : Desc;
}
}
}
And in the repeater eval DescSummary
Try
<%# Eval("desc").ToString().Length > 150 ? Eval("desc").ToString().Substring(0, 150) : Eval("desc") %>
Greetings,
I have a control and list of variables and I want in the control property to be assigned to the variable value directly in the page not from the back code, something like this
My global variables
public string Banana = "banana_pie";
public string Apple = "apple_pie";
in my custom control instead of:
<uc:LoadPie id="pieBanana" type="banana_pie" />
To this
<uc:LoadPie id="pieBanana" type="<%=Banana %>" />
so is there a way or just assign the property in page back code.
Thanks
You can do it like this using data binding syntax.
<uc:LoadPie id="pieBanana" type='<%#Banana%>' runat="server"></uc:LoadPie>
But then in your code behind you have to call
pieBanana.DataBind();
in the page load in order for the databinding expression to be evaulated.
But if you are going to do this then you might as well assign the property in the page load.
I think you should go with a property (protected should be enought, but I'll say public in the following snippet) in your code behind:
Public Property myBanana() As String
Get
Return Pies.Banana;
End Get
End Property
Then you can use it in your controls, for example:
<uc:LoadPie id="pieBanana" type="<%= myBanana%>" />
Not quite what you want, but how about:
<% pieBanana["type"] = this.Banana %>
I am dynamically generating a table to present some tabular data. Normally I would not go near tables, but for this kind of data it is appropriate.
I am noticing my view code is becoming very spaghetti like. Assigning classes on cells and rows in the body of loops is starting to look just awful (bad flashbacks to my asp 3.0 days).
I looked into using the runtime serialization to json for my DTOs and then using a JQuery plugin for templated rendering of JSON. It seems like a "cool" idea, but is more of a programming exercise than I care to do at the moment.
How are people building more involved UIs with asp.net mvc?
If you're concerned about how your view markup mixed with code looks, you can try an alternate view engine:
Spark
NVelocity
Brail
NHaml
All of these view engines take different approaches to combining code and markup that can make your view markup "cleaner".
I've written some HtmlHelper extensions to help with table building. These extensions use a TagBuilder in code to generate the rows according to the values and HTMl attributes defined. The view code is considerably cleaner using these extension methods and the extension methods themselves are testable to ensure that they produce clean code reliably.
Sample view code:
<% var alternating = false;
foreach (var model in Model) { %>
<% using (Html.BeginTableRow( new { #class = alternating ? "alternating-row" : "" } )) { %>
<%= Html.TableElement( model.Column1 ) %>
<%= Html.TableElement( model.Column2, new { #class = 'some-class' } ); %>
<%= Html.TableElement( model.Column3 ) %>
<% }
alternating = !alternating;
%>
<% } %>
In addition, I've actually create a grid control that will generate a styled table using the above and most of my view code consists of rendering the grid control with the proper model.
<% Html.RenderPartial( "GridControl", Model, ViewData ); %>