Click here to Skip to main content
15,039,021 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi everyone,

I am studying MVC and was following an example. I am also not expert with Lambda expressions and ANonymous types, although I have read and know the basics. However I got trapped and could not continue. I need help about this code snippets below. Can someone please answer my question ?

1. how the X was inferred to be an INT ?

2. What is the return of "new { page = x }" ?

3. What is the return of "Url.Action("List", new { page = x })" ?

4. What is the return of "x => Url.Action("List", new { page = x })" ?

5. This call, pageUrl(i), what does it do and where is the method declared ?


HTML
<div class="pager">
    @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {  page = x }))
</div>



C#
 public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl)
 {
             StringBuilder result = new StringBuilder();
             for (int i = 1; i <= pagingInfo.TotalPages; i++)
             {
                 TagBuilder tag = new TagBuilder("a"); // Construct an <a> tag
                 tag.MergeAttribute("href", pageUrl(i));
                 tag.InnerHtml = i.ToString();

                if (i == pagingInfo.CurrentPage)
                     tag.AddCssClass("selected");

                result.Append(tag.ToString());
             }

            return MvcHtmlString.Create(result.ToString());

}

Thank you so much.
Posted
Updated 24-Aug-14 3:22am
v2

Html.PageLinks(...) is the invocation of your custom HTML Helper used for pagination. The HTML Helper class returns a string for building HTML tag link. This static helper class is used by PagingInfo model. Each time a user clicks the page number, it is passed to PagingInfo as currentPage parameter value. And this value will be used as X.

Url.Action("List", new { page = x }) create an URL by using the given action name ("List") of the current controller and the given parameter for the route ( new { page = x }), so the result will be something like this: "YourCurrentController\List\?page=5", supposing that the user have clicked on 5th page (and X will be matched with 5).
   
v2
Comments
guishell 24-Aug-14 4:43am
   
Thank you so much for your reply Raul. I got your very helpful points. But I have 2 clarifications:

1. if Url.Action("List", new { page = x }) returns a string something like "YourCurrentController\List\?page=5", why is the PageLinks method expected the result as "Func<int, string=""> pageUrl" and inside it, he called pageUrl(I)as if it is a method ?

2. When the user click "5", and its passed to the action method, how did the view knew that 5 should be put into x ? (I did not see it use any sort of ViewBag? )

I am really sorry and thank you for helping a newbie like me. I really want to learn MVC and I got stuck here.
Raul Iloc 24-Aug-14 5:19am
   
1.Maybe I was not so clear, the invocation of the HTML Helper has as parameter the lambda expression that dynamically use the X parameter and the given expression to build the returned URL; the parameter of type lambda expression, named "pageUrl", define that the expression must have an int as input parameter and a string as output, so the given "Url.Action(...)" will be used to build the returned URL as string.

2.The construction of the "anchor" tag ("TagBuilder" object from your custom HTML code) associates for each page the integer that will be sent as parameter when the user will click on it. So the anchor tag is build as HTML and when the user will click on it the browser itself will invoke the associated action that already has the INT parameter value inside it.

You could see details about the generated HTML of your View by using "View Page Source" in your browser.
guishell 24-Aug-14 7:20am
   
Thank you so much Raul. You have helped me a lot in my adventure. Thanks. :)
Raul Iloc 24-Aug-14 12:42pm
   
Welcome, I am glad that I could help you!
guishell 24-Aug-14 9:03am
   
Thank you so much for helping me out Raul and Sergey.
For all the newbies who will be facing the same difficulties for this "supposedly simple" code, I am sharing what I learned with the help of our developer friends:
<div class="pager">

@* new { page = x } returns an ANONYMOUSLY-typed "OBJECT" *@
@* Therefore, the Url.Action here uses the "string, OBJECT" overload *@
@* X here is of type INT, as it has been infered from the PageLinks method (Func<int, string=""> ...) in advance*@

@Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x }))

</div>

// This extension is called by the view. Once called, it checks the total number of pages. It then CREATES LINKS with HREF values ("/?page=1" , "/?page=2" and so on).
Also, while iterating, it checks if the the link it is processing is the one "selected" by the user and if it is, applies a CssClass which "underlines" the link. When it finishes creating ALL THE LINKS, it is RETURNED TO THE VIEW FOR RENDERING.

// This method extends HtmlHelper class
// pageUrl is a parameter of type "a Function that expects an INT parameter and returns a STRING". The parameter of type lambda expression, named "pageUrl", define that the expression passed to it must have an int as input parameter and a string as output. So the parameter passed by the view, "x => Url.Action("List", new { page = x })" exactly matches this and it will be used to build the returned URL as string.

// -----------------------------------------------------------------------
// This whole expression is a LAMBDA EXPRESSION which passes-by reference
// (a function pointer) a function that accepts INT and returns a STRING,
// to HtmlHelper.PageLinks(). The Function that was "Pointed-by-Referece"
// is the Url.Action(...).
// -----------------------------------------------------------------------
// x => Url.Action("List", new { page = x })
// -----------------------------------------------------------------------

public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string=""> pageUrl)
{

StringBuilder result = new StringBuilder();
for (int i = 1; i <= pagingInfo.TotalPages; i++)
{
// Construct an tag
TagBuilder tag = new TagBuilder("a");

// This is a call to the referenced function(or the pointed function which is x => Url.Action("List", new { page = x }) ).
// So this call, pageUrl(1), translates to "Url.Action("List, new { page = 1 }")" , returns "/?page=1"
// You can you View Source COde to see the href value that his function generates
tag.MergeAttribute("href", pageUrl(i));
tag.InnerHtml = i.ToString();

if (i == pagingInfo.CurrentPage)
tag.AddCssClass("selected");

result.Append(tag.ToString());
}

// At this point, ALL LINKS have been created and their HREF values have been properly populated
//result.ToString(); CONTAINS < a class="selected" href="/?page=1">1 </a > < a href="/?page=2" > 2 </a> <a href="/?page=3">3 </a>

return MvcHtmlString.Create(result.ToString()); // encodes for proper html rendering

}
1) It depends on what is X and the code using inference. You should understand the main thing: inference is totally unrelated to anonymous types.

2-4) Do the following. Assign the expressions you show to some variable. Under the debugger, stop after assignment, and inspect this variable. Say, of this is X, inspect: X and X.GetType(). You will get all the answers.

5) The method is declared in your second code fragment. :-)
The first code fragments calls this methods and inserts the string returned (the result of the calculation is some HTML string) into the content returned as HTTP response.

—SA
   
Comments
guishell 24-Aug-14 4:44am
   
Thank you so much for your help Sergey.
Sergey Alexandrovich Kryukov 24-Aug-14 13:10pm
   
You are very welcome.
Good luck, call again.
—SA
Do not understand why Url.Action("List", new { page = 1 })" , returns "/?page=1"
   
Comments
CHill60 25-May-15 17:11pm
   
This is not a solution to this question!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900