Posts Tagged ASP.NET

ASP.NET Controls, How I Hate Them

MSDN Error
Image by ttrentham via Flickr

I’ve always, for some reason, felt innately that PHP allowed me more control over my code than ASP.NET. My brain kept saying “but .NET is more organized! It compiles! It’s faster! It’s easier to write,” but my mind kept saying “PHP lets me do what I want how I want it… screw .NET!”

What I finally figured out was that I love C#, I even like the .NET framework, but I hate is, in fact, ASP.NET.

Every time I see an example of simple, elegant code, the most complex control on the page is a label or a panel. While the intentions behind FormView may be good, writing my own forms and hooking them up saves hundreds of lines (literally- I just refactored almost 800 lines of code into 150 by removing a formview) as well as reduces complexity and maintenance (now I no longer have to maintain view and edit and whatever other modes FormView has.) ASP.NET perhaps made sense in a day before OO principles and ORMs came into play; the controls were written for the same kind of people that use the drag-and-drop design mode. Easy to slap down haphazardly, not so easy to maintain.

We replaced every ASP.NET Ajax control we used anywhere (after I evangelized it, to my chagrin) with jQuery after about 6 months of use; while the controls did what we needed on the surface, underneath there was always some caveat, like the linked DropDowns needed web services, or the datepicker control had missing options… there was always something somewhere that I needed a bit of flexibility on that just wasn’t there, or was buggy. It seemed very odd for it to be out of beta in such a state. So, I ended up starting my own control library using jQuery, and now it’s easily extensible, easy to modify from the client, and I can control the markup.

Oh, and the markup… don’t get me started on the markup. Tables for everything. I can’t rearrange the otherwise useful Wizard control because it’s so static in its display.

So, I guess the point I’m trying to make is, that the longer I use .NET, the less and less I use the complex controls and the more I roll my own. Because it’s easier.
Kind of ironic.

Reblog this post [with Zemanta]

Tags: , , , , , , , ,

User Controls Rock: Legos and Fake Ajax Master Pages

Let me start with a simple statement: user controls are absolutely fantastic.

If you haven’t delved into the realm of the .ascx, then let me briefly explain the two big benefits that have been relevant to me recently:

  • Totally reusable code
  • Emulate master pages; only with this, you can use the Ajax control toolkit to do it

On the first point, the reusable code point, this is the biggest. It’s the entire reason behind user controls. It lets you chunk out code that you use all over, and use it in several places; it’s a fundamental of object oriented development. Let’s do an example.

Say you have a piece of code that goes to the database and retrieves data on a member. That data is then put into a styled gridview, for the administration side of a website. But, you also have an area in a members section where a user can edit their own information (more like a formview); and, on the normal web display, casual users can browse through usernames and user roles in a paged gridview.

Don’t write the same code thrice! (or even twice!) Rather, make a user control to do all the work for you, and place it in each of your pages. This is how I’d do it:

For the sake of this article, I’m assuming you’re using a list of “Member” objects. Use whatever.

-Make a public class-level property in your control called “ReadOnly”, a bool.
-Make a public class-level method in your control called “Intialize”, which takes an IList of Member objects
-If the IList has one object, add a FormView to your control, and databind it. Otherwise, go the Gridview route (doing this all from the codebehind would keep your code cleaner and keep you from having an extra control rendered, although you could do this in the .ascx if you really wanted to; just set one to visible=”false” to the one you’re not using)
-Create all of the appropriate methods for your control for delete, update, insert, etc. and set up your formview or gridview accordingly (of course, only update for our member’s area FormView!)
-If ReadOnly is true, don’t add edit, insert, or delete buttons to your formview/gridview. (Easy enough; could set visible=”false” on the fields, or just not add them at all)

And, then, back on your three main pages, register and use your control.  Set the ReadOnly property (if it’s a bool, you should even get IntelliSense for true/false), and then on Page_Load, call Intialize on the control, passing through the IList of Members that you pulled down.

The reason we’re calling the data on the page, rather than the control, is so that the control can remain “dumb” and doesn’t need to know whether it’s a member, admin, or web display control. The less logic in the control, the better; just spit out the lowest common denominator.

Ok. Now that we’ve hit the reusable control side, let’s hit the fake-an-ajax-master-page part.

As you may or may not know, even if you wrap the ContentTemplate in a MasterPage, it still reloads every page change. This is because the MasterPage gets loaded after the rest of the page, and is treated like a control. So, if you change pages.. it loads the page, and then says afterwards, ‘oh, yeah, that was Ajax. Oh well.’

The cool thing you can do, is make one default page, and inside of that have user controls in place of your pages, something like this:

-Make your default.aspx page
-Create user controls; however, rather than logic in Page_Load of the control, put it all in a public class-level method you call Initialize.You’ll see why soon.
-Put all of your controls into your default.aspx page, with visible=”false”.
-On the onclick of your navigation buttons, run the Initialize on the control, and set it’s visible property to true, and all the others to false.. I might alternately suggest using Command and a single method rather than Onclick and seperate methods for each button, so you can pass through a CommandName, which you can then use in a switch statement and know what button you hit.

Ok. Now that we have our fancy Ajaxy page, you may be wondering: why not just visiblity? Why this Initialize thing?

This is because ASP.NET will fully render the controls, visible or not. Which means that if you have 10 pages, it will load those 10 pages and display one; which is a big performance hit on the server, especially if you’re loading database data into each of those 10. Having to explicitly call Initialize avoids this. It also allows you to pass through a common parameter to each of the controls (say, a title string that displays at the top of each control) .

Controls can certainly do much more than this; but these are the biggies for me. Have any .ascx uses of your own?

Tags: , , , , ,

ASP.NET DataPaging Control with Data Sources Set in the Codebehind (Including LINQ)

After eight (well, seven.. lunch) torturous hours, trying to figure out something so simple, that should have been so easy, I’m finally done. (Spoiler: skip to the bottom to figure out how to fix the paging-control-one-step-behind issue)

My scenario: I had an IList of objects, populated via some nHibernate magic. How I got the data isn’t the important thing; just mattered that I had an IList of some object that I needed to put into some kind of paged display. The tricky bit was doing it through the codebehind, rather than setting up an ObjectDataSource for it. I tried several different methods, but kept coming back to one solution: a ListView with the new DataPager control.

It should have been pretty easy; the the DataPager control isn’t terribly hard to set up. Just throw in the control, populate the ID, runat, pagesize, and pagedcontrolid (the control that it adds paging to). That was attached to a listview, with an id and runat, and it had a layout template, item template, and alternatingtemplate inside of it. It all looked something like:


<asp:DataPager ID=”dpDataPager”
runat=”server”
PageSize=”5″
PagedControlID=”lvItems”>

<Fields>

<asp:NextPreviousPagerField NextPageText=”next »” ShowFirstPageButton=”true” ShowLastPageButton=”false” ShowNextPageButton=”false” ShowPreviousPageButton=”true” />

<asp:NumericPagerField ButtonCount=”10″/>

<asp:NextPreviousPagerField PreviousPageText=”« previous” ShowFirstPageButton=”false” ShowLastPageButton=”true” ShowNextPageButton=”true” ShowPreviousPageButton=”false” />

</Fields>

</asp:DataPager>

<asp:ListView ID=”lvItems”
runat=”server”>

<LayoutTemplate>

<span id=”itemPlaceholder” runat=”server”></span>

</LayoutTemplate>

<ItemTemplate>

<li class=”even”><%# Eval(“Caption”) %></li>

</ItemTemplate>

<AlternatingItemTemplate>


<li class=”odd”><%#
Eval(“Caption”) %></li>

</AlternatingItemTemplate>

</asp:ListView>

And (the important bits) in my code behind:
In the Page_Load, I had


if
(!IsPostBack)

{

bind();

}

And after the Page_Load method, I had

private void bind()

{

IList<Content> content;

int id = Int32.Parse(Request.QueryString["id"]);

FeatureValues
fv = FeatureValues.AudioGuestBook;

content = ContentWrapper.GetContent(id);

lvItems.DataSource = content;

lvItems.DataBind();

}

And all was fine, and it rendered nicely. Except when you clicked to change a page, that is.

From there, weirdness ensued; it was out of sync, always one step behind.  If you clicked page 2, nothing happened. If you then clicked page 3, it went to page 2. If you went back to 1, it went to 3… and so on.  This led to a wild chase through several hours and pots of coffee using Google, which finally led me to a forum post.  And there the answer was! It suddenly became clear: a solution which was, in the end, rather simple, if a little obscure. I added:

onpagepropertieschanging=”lvItems_PagePropertiesChanging”

to the ListView in the .ascx file, and

protected void lvItems_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs
e)

{

this.dpDataPager.SetPageProperties(e.StartRowIndex,
e.MaximumRows, false);

bind();

}

in the codebehind. This caused a change in the page to update both the listview and the data shown – something that I had been trying to find in a handler for the paging control, rather than the listview.

So there you have it: How to get a paged listview by using a data source set in the codebehind.

Tags: , , , , ,