views:

597

answers:

4

Main question: Is there a better way to accomplish creating a reusable control?

So the idea was to make a paging control to basically stop from having to keep typing out practically the same markup on multiple views. It's taking this:

 <%= Html.ActionLink("First", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.FirstPage, amountToShow = Model.AmountToShow }))%>
 | 
 <%= Html.ActionLink("Previous", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.PreviousPage, amountToShow = Model.AmountToShow }))%>
 |
 <%= Html.ActionLink("Next", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.NextPage, amountToShow = Model.AmountToShow }))%>
 |
 <%= Html.ActionLink("Last", "Details", new RouteValueDictionary(new { parentForumId = Model.TopicId, pageNumber = Model.LastPage, amountToShow = Model.AmountToShow }))%>

And turning it into this:

<%= Html.Pager("View", "Controller", "RouteName", Model, new Dictionary<String, Object> { {"parentForumId", Model.ParentForumId}}, " ") %>

Where as you can see I pass in the needed view, controller, route name, model, and a dictionary used to add request variables onto the url for the link.

What I found is that I would have to make an extension method for the HtmlHelper class and essentially take what in ASP.Net was a full class (with nice methods like CreateChildControls) and jam it all into one main method that returns a string.

Is this the preferred way of doing this? One nice thing of the ASP.Net way was markup to class as in you have the html markup tag that would translate markup properties to class properties. It generally made for cleaner mark up but admittedly "fake" html. In this situation I have a method with what could be a mile long signature pumping out html. And since I don't have a base WebControl class, every control I make will have to have method calls with the same basic needs like say CssClass or ID.

Now with that being said, I suppose I could pass in an attributes dictionary since the HtmlHelper.GenerateRouteLink method that I'm using calls for one anyhow, but this really seems really messy.

Is there a better way to do this?

+1  A: 

You might want to check out Martijn Boland's Pager control for some inspiration.

Personally, for my reusable grid control I use a class that contains all information needed to generate a grid with paging, sorting, ... and I call partial views to generate the seperate elements (Pager, Column selection, pagesize selection, ...), passing the information they require to them.

This way I can easily extend the grid with custom stuff. For example I can create a Mygrid_editableTable.ascx view to show textboxes instead of just text, and add an extra column with a submit button. This while continuing to use the paging, page selection, ...

Thomas Stock
Yeah that's kind of what I did (Noland's Pager) as I have a model base class that holds things like next page number and last page number. The view itself is "typed" with that model class.
Programmin Tool
Will look into partial views as suggested by Robert Harvey and by you.
Programmin Tool
+2  A: 

You could put it in a partial view, instead of creating a helper.

Robert Harvey
+5  A: 

First, its all ASP.NET...one is MVC, the other is WebForms. Took me a sec to realize what you were saying when you keept saying the "ASP.NET way". :P

The idea with an MVC is that your view is "dumb", without any real behavior outside of the absolute bare bones basics to render data. In WebForms, views were tightly bound to the behavior that rendered them and handled view events. This, while convenient, made WebForms views very difficult to unit test since view content and behavior were linked and sometimes blended.

The reason MVC views use things like HtmlHelper and AjaxHelper is to keep behavior as separated from the view as possible. Unlike a user or server control in WebForms, you can fully unit test an Html.Pager extension method, since the logic is pure code, without blending those UI concerns or being linked to a bunch of non-testable UI level types. The same general rule applies to MVC controllers to...they are just code, without being linked to events or anything like that.

It may be less convenient in the short run, as you are currently used to the old WebForms way of doing things. Give yourself some time, though, and you will likely start to realize the benefits that MVC's preferred way of doing things brings to the table. Writing a Pager extension method on HtmlHelper is indeed the preferred way to do things with MVC.

As for the mile-long signature bit...do a search (try out Bing.com!) for fluent style interfaces and HtmlHelper. The fluent style is starting to take a strong hold in environments like MVC views where you are likely to have huge signatures. The general idea is based on method chaining, kind of like jQuery, and can shorten those long signatures into a series of much shorter and more meaningful chained method calls that set up your html helper, with a final call to a .Render method or something similar.

jrista
haha yeah sorry, I still think ASP.NEt versus MVC
Programmin Tool
+1  A: 

We end up using html helpers for paginators as they are easy to unit test. Pagination business requirements can be finicky.

"Show less than 35 links as numbers, then group by 20s unless there are more than 100 pages of results, in which case group by 100s...but on Thursdays, or to GoogleBot, show them as... etc."

Plus our SEO guys keep changing their mind on what shape urls get the most juice. In such a situation, something unit testable is a must!

brian b
Well luckily for now it's only a simple first, previous, next, last thing and all that is done on the controller and the page number values are sent through the model. I can see your point though.
Programmin Tool