July 2004 - Posts

As Promised, the Article on the RoundedCorners Web Control
27 July 04 08:56 PM | Scott Mitchell

In my last blog entry I mentioned how I had created a Web control that displays a box with rounded corners, using GDI+ to dynamically create the corner images based on the box's properties (background color, border color/style/width, etc.). I have just published an article on 4Guys about this Web control - Introducing the RoundedCorners Web Control - including the complete source code for the control. There are a couple of minor issues with the control that I hope others will be able to improve upon:

  1. The design-time experience is suboptimal, as the rounded corner images are not created during design-time. The result is a box sans rounded corners!
  2. The control currently uses an HTML <table>; it'd be nice to have someone upgrade it to use CSS and have adaptively choose what approach to use based on the visiting browser.
  3. As Jeffrey Palermo mentioned in the last blog entry's comments, it would be nice to have smoother corners.

As always, I invite you to check out the live demos and share any feedback/suggestions/comments you may have. You can also check out my Code Projects page, which lists the open-source ASP.NET Web controls I've created.

Filed under:
A Web Control for Displaying Rounded Corner Tables
26 July 04 07:39 PM | Scott Mitchell

A common Web UI element among profressionally-designed Web sites is that of a table with rounded corners. To see what I mean, just check out the boxes on the left-hand side of Amazon.com, or the boxes on the left-hand side on DataWebControls.com. Creating such a rounded corner interface isn't terribly difficult. Essentially, you use a graphics editing program to create the rounded corners. Then, use an HTML <table> with three columns to display the left corner, the middle, and the right corner.

If you're anything like me, you find using graphics editing programs synonymous with a root canal. I'm just not a artsy kind of guy. Anywho, I created a Web control that utilizes GDI+ to dynamically create those rounded corners for you, and will be writing up an article on 4Guys showing how to use the custom server control and the code behind it. For now, you can marvel at these live demos. I'll post an entry here once the 4Guys article is up (hopefully by late afternoon tomorrow).

(I'll leave you with a teaser: the dynamically generated images (which are only created on-demand, and actually saved on the Web server's file system so that they aren't created every time someone views the page) are GIF files that use a transparent palette color and employ quantization in order to increase the quality of the GIF and decrease the file size. These two issues are what took up the vast majority of the time in creating the control... more on these topics in the coming 4Guys article!)

Filed under:
Question: I set my page's EnableViewState property False; why is there still a __VIEWSTATE hidden form field?
23 July 04 02:54 PM | Scott Mitchell

ANSWER: A while back I wrote an article for MSDN online titled Understanding ASP.NET View State, and blogged about the article in this past entry. I recently noticed a comment in that blog entry from Matthias Cavigelli, asking:

When I disable the ViewState property of the page, I still have the hidden field __VIEWSTATE in the html code. Could you explain why it's still there although it's not enabled?

What Matthias is referring to is the EnableViewState property, which is defined in the System.Web.UI.Control class (which means that all ASP.NET server controls have this property, including the Page class from which all ASP.NET Web pages are derived.) This property defaults to True, which means that, by default, a control should track its view state and save its view state during the SaveViewState stage of the page's lifecycle. By setting EnableViewState to false, a control is saying, "Don't bother recording my view state."

Setting EnableViewState to False on certain state-heavy controls is a good way to trim the size of a page's view state. Of course, you must take care when tweaking this property, since the state-heavy controls typically rely on the view state to maintain their functionality. Here's a good example of when you can set EnableViewState to False: when you have a DataGrid Web control on a page that simply displays data, and where the DataGrid's properties are not programmatically changed on postback. (Note: if this page does have postbacks you'll have to make sure to rebind the database data to your DataGrid on every postback.)

If your page does not perform any postbacks at all, having view state is a big waste. So, you might as well set the Page class's EnableViewState to False, so that no view state is saved for the entire page. Or so you'd think. If you set EnableViewState to False for the page, you'll still get a hidden __VIEWSTATE form field, although it will be pretty small. Why does this hidden form field exist at all?

To answer this question it is important to realize that view state really is paramount to Web Forms, not the Page class. (A Web Form is a server-side <form> tag, which is represented in the .NET Framework via the System.Web.UI.HtmlControls.HtmlForm class.) If a Web Form exists, there typically needs to be a hidden __VIEWSTATE form field. But the Web Form does not know the complete view state of the page. The Page class, for instance, has a ViewState property, into which a page developer can store items into the view state. The Web Form, obviously, is ignorant about this. So there's this chicken-and-egg thing going on here - the Page knows how to completely represent the view state, but it's the Web Form that cares about it, not the Page. The end result is that the Page class is responsible for generating the hidden __VIEWSTATE form field, but it's the Web Form that knows whether or not this is needed.

To overcome this hurdle, the Page class needs some way to know whether or not the __VIEWSTATE form field needs to be emitted or not. To allow for this, the Page class provides a public RegisterViewStateHandler() method; if this method is called during the page lifecycle, a __VIEWSTATE hidden form field will be emitted, even if the Page class's EnableViewState property is set to False.

From a Web Form's perspective, it always needs to save view state. Well, this is the way the Web Form class was programmed by Microsoft. You can see this by examining the HtmlForm class's OnInit() method:

protected override void OnInit(EventArgs e)
{
      base.OnInit(e);
      this.Page.SetForm(this);
      this.Page.RegisterViewStateHandler();
}

Personally, it would seem to make more sense to me to have Page.RegisterViewStateHandler() called only if Page.EnableViewState is true, but there may be a reason behind this that I haven't seen. Anywho, when the Web Form is rendered, it calls an additional two of the Page class's methods:

  1. OnFormRender() - this adds the __VIEWSTATE hidden form field along with any registered hidden form fields or script blocks registered via Page.RegisterClientScriptBlock().
  2. OnFormPostRender() - this adds any script blocks registered via Page.RegisterStartupScript() and any client-side arrays registered via Page.RegisterArrayDeclaration().

You may still be wondering why when the Page's EnableViewState is False that the __VIEWSTATE hidden form field has anything in it. Well, if you take a look at the Page class's SavePageViewState() method, you'll see:

internal void SavePageViewState()
{
      if (!this._needToPersistViewState)
      {
            return;
      }
      Triplet triplet1 = new Triplet();
      int num1 = this.GetTypeHashCode();
      triplet1.First = num1.ToString(NumberFormatInfo.InvariantInfo);
      triplet1.Third = this._registeredControlsThatRequirePostBack;
      ...
      triplet1.Second = base.SaveViewStateRecursive();
      
      this.SavePageStateToPersistenceMedium(triplet1);
}

So what you see her is the following: if _needToPersistViewState is False, then nothing is saved. Well, this flag is set to True when the Web Form calls Page.RegisterViewStateHandler(). So a Triplet is built up, with the first item containing the page's hash, the third item containing an ArrayList of Web controls that require a postback. Now, the second item is where the meat of the view state comes from - this is the sum of the view state of the controls in the page. But if EnableViewState is False for the page, SaveViewStateRecursive() returns null.

So even if you set the Page's EnableViewState to False, you'll still get a __VIEWSTATE hidden form field with the Page's hash and ArrayList of controls that require postback. I still don't see why this is needed, but there is likely a good reason.

In an upcoming article of mine for MSDN online, I talk more about the Page class's methods for registering client-side elements - scripts, arrays, hidden form fields, etc. Keep your eyes peeled on the ASP.NET Dev Center!

Does the VS.NET Designer Hate Me?
23 July 04 11:29 AM | Scott Mitchell

This is more of a rant than anything else, but does anyone know why if I type in a Repeater in the HTML view in VS.NET 2003 like so:

<asp:Repeater Runat="server" ID="...">
<HeaderTemplate>
<p><hr /></p>
</HeaderTemplate>
<ItemTemplate>
...
</ItemTemplate>
<SeparatorTemplate>
<p><hr /></p>
</SeparatorTemplate>
</asp:Repeater>

When I go to the Design view it gives me that “Error in Server Tag” message. But, if I remove the HeaderTemplate and SeparatorTemplte's contents, then it works fine. Why can't the Designer handle that simple bit of HTML? What gives!?!

Ok, I feel better now.

Filed under:
On a Related Note - Large Web Forms
22 July 04 12:22 PM | Scott Mitchell

Earlier today I posted about large view state issues. Another issue that faces me with this current project I'm working on (which goes hand-in-hand with the large view state problems), are large Web Forms. By this I mean the client wants a single Web page with a gaggle of form fields. By “large” I'm talking about, in some cases, over 300 Web controls on a single page. (For the record, this is the client's specs, not my design!)

Has anyone worked on projects before where Web Forms of this size were common? There's a number of issues I'm having that are a bit annoying, and was wondering if there are any tips/hints in helping circumvent these problems. Some of the annoyances of large Web Forms include:

  • Visual Studio .NET drags. Switching from HTML view to Design view means it's time to go downstairs and get a soda.
  • When visiting the page for the first time after any changes have been made to the HTML portion, it takes a good four or five seconds for the ASP.NET engine to autogenerate the class that derives from the code-behind class. This won't be an issue in deployment, but is annoying when you need to make a small change to the HTML in a page.
  • View state can get very large, as I alluded to earlier. This is especially the case when using DropDownLists.
  • The code for populating these Web controls with database data and, conversely, reading the data from the controls when saving, can be cumbersome. Usually if I have a series of related controls I'll give them some sort of similar ID value, and then use a loop and FindControl together to snap through a dozen or so related Web controls in three lines of code as compared to 12.

Any tips or helpful suggestions appreciated. Thanks!

Filed under:
Largest. ViewState. Ever.
22 July 04 08:37 AM | Scott Mitchell | 1 comment(s)

The ASP.NET DataGrid Web control is notorious for its hefty view state size, but the DropDownList control can hold its own weight as well, especially when it contains a lot of items. For example, a page containing nothing but a DropDownList populated with ~100 items from a database will yield around 10 KB in view state. While 10 KB might not seem like much, remember that view state is a two-way penalty - it is sent down with the page's HTML and sent back during postback, thereby increasing both the download and postback time for the end user.

I just finished a page that, I think, will hold record as having the largest view state. Ever. Working on a site for a client and he needs a page that has over a dozen DropDownList controls, and each DropDownList has, believe it or not, upwards of 1,000 items. End view state? Over 800,000 bytes. In total, the page was over 2.5 MB in size. What does this mean for an average dialup user? Well, they'll have to wait nearly six minutes to download the page, and eight minutes to postback (two minutes to upload the 800 KB of view state, six minutes to download the 2.5 MB again).

Of course, I cut the view state down to a few KB by turning off view state for the page. It wasn't needed since I wasn't programmatically changing the state of the controls on the page, nor was I using the SelectedIndexChanged event of the DropDownList. But still, the page weighs in at 1.7 MB, which is still prohibitively large (even though all users are really on an intranet).

Your Daily Tip to Save Yourself 15 Minutes of Wasted Time
20 July 04 12:24 PM | Scott Mitchell

Thought I'd jot this donw - hopefully someone out there will read it and save the 15 minutes I lost to working on this little “gotcha” problem.

Scenario: You have a DataGrid with two columns. The first is a BoundColumn, the second a TemplateColumn. In the TemplateColumn you have a RadioButtonList. The idea is to have the user select precisely one option from the second column for each item in the first one. Basically, the DataGrid markup looks like:

<asp:DataGrid ...>
<Columns>
<asp:BoundColumn ... />
<asp:TemplateColumn>
<ItemTemplate>
<asp:RadioButtonList id=”radList” ... />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>

Now, this RadioButtonList needs to be bound to a list of options. Since the options are the same for all items in the DataGrid (and therefore not specific on the particular row), you figure that you'll use the DataGrid's ItemCreated event to do this. (FIRST MISTAKE!) The event handler looks something like:

Sub MyDataGrid_ItemCreated(...) Handles MyDataGrid.ItemCreated
If e.Item.ItemType = ... Then
'Get a reference to the RadioButtonList
Dim radList as RadioButtonList = CType(...)

'Bind the data
radList.DataSource = ...
radList.DataBind()
End If
End Sub

The above will work just fine, although it is a bit inefficient (more on that later). Now, if you were to see the DataGrid, you'd see a series of rows with the second column in each row with a set of radio buttons. However, no radio button is selected by default. Ok, easy enough, go and add radList.SelectedIndex = 0 right after the radList.DataBind() call, right? Well, you'd think that work, but it doesn't. No error, of course, just no selected radio button.

Now, if you are like me, you spend the next 15 minutes thinking about this, opening Reflector, reading the docs, and being generally unproductive.

If you want to waste less time, you would simply move this code to the ItemDataBound event rather than ItemCreated. After ItemCreated, the DataGrid assigns the DataSource record to the DataItem property of the current DataGridItem (e.Item) and then calls the DataBind() method of that DataGridItem. The DataGridItem propogates the DataBind() call down to its child controls, meaning the RadioButtonList will have its OnDataBinding event fire. What happens there? Well, it sees that the DataSource for the RadioButtonList is not null, so it clears out the RadioButtonList items, and rebinds the data! This, of course, has the negative side-effect of clearing out the SelectedIndex setting.

Solution: anytime you find yourself calling DataBind() for a Web control that exists in a TemplateColumn of the DataGrid, make sure you are doing so in the DataGrid's ItemDataBound event, otherwise the data will be bound twice to the Web control, which will not only be less efficient, but might have negative side-effects, as seen here.

Filed under:
A Row-Highlighted, Row-Selectable Custom DataGrid Control
19 July 04 10:26 AM | Scott Mitchell

It's funny what you find lying around your hard drive. I was poking through my “Misc ASP.NET Control Projects” folder and stumbled across a row-highlighted, row-selectable custom DataGrid control. Basically, it allows you to specify a background color and whenever the user moves her mouse over a DataGrid row, the row turns that color. Plus, by setting the RowClickEventCommandName property you can indicate that if the row is clicked it should cause a postback and trigger a particular DataGrid event. You can see what I mean by checking out this live demo.

Anywho, when I found this I project I started racking my brain - what in the world did I creat this for? It was created on May 19, 2004. Was it just for fun and to learn something new? Or was it meant to be an article for 4Guys? Or was I planning on building an article around it for MSDN or asp.net PRO? Since I couldn't answer that question, I decided why not make a 4Guys article out of it. So here you go: Creating a Row-Selectable DataGrid Control.

For more custom controls I've created, check out My Code Projects.

Filed under:
An Idea for Commuters
17 July 04 06:35 PM | Scott Mitchell

This idea was put forward by my wife the other night (who commutes, by the way; I get to work from home). Anywho, she noticed that traffic is bad in both directions at both times of the day. So clearly there are people who live where she works who drive down to where we live to work, as she treks up to where they work. And surely there must be similar jobs up where she works as there are near us. So why not find someone who lives up where she works who has a similar job, and switch?

Filed under:
New Article on UsernameToken Authentication with the WSE 2.0 Toolkit
14 July 04 11:19 AM | Scott Mitchell

The latest 4Guys article was published today, and looks at implementing UsernameToken authentication using the WSE 2.0 Toolkit. In an earlier article I wrote about the Web Service Enhancements (WSE), a set of extended Web service standards defined to help businesses implement common Web service needs not addressed by the core standards (such as security and messaging). Anywho, Microsoft has been kind enough to create a free toolkit to assist developers in implementing the WSE standards. This toolkit, called the WSE 2.0 Toolkit, was officially RTMed back at TechEd this year (which I blogged about).

The main bulk of the WSE 2.0 standards address security standards. Using WSE, one can implement secure Web services using industry-defined standards. One of the security-related standards for WSE is the UsernameToken authentication standard, which spells out how a client can send along a username and password to a Web service for purposes of authentication. This latest 4Guys article - available at http://aspnet.4guysfromrolla.com/articles/071404-1.aspx - shows how easy it is to implement this standard using the WSE 2.0 Toolkit.

This 4Guys article is the ninth part in an ongoing series titled An Extensive Examination of Web Services...

Going to Try My Hand at Fiction... Eventually
13 July 04 10:52 AM | Scott Mitchell

Ever since I was in grade school I've always had a fondness for writing. I used to fill countless spiral notebooks with make believe stories I invented in my head, but it wasn't until the family computer - purchased when I was 10 - and learning how to touch-type that I was able to really start churning out the works. I wrote strictly fiction from grade school through high school, and a bit into college, but stopped once I really got into computer science. I didn't stop writing, I just stopped writing fiction. Instead I turned to technical writing, starting 4Guys in 1998 and churning out, at times, an article per day. (I blogged about this shift from fiction to non-fiction previously, in Do You Write Fiction?)

I've done non-fiction pretty much exclusively for the past six years. I've authored numerous books, magazine articles, and probably more than 1,000 online articles. Taking a cue from Coca-Cola's bold move in the late 80s in rolling out “New Coke,” I've decided that it is time to change tracks, to get back into writing fiction. And when I saw, “getting back,” I don't mean just writing a short story here or there for my own personal enjoyment. No, I mean writing a novel and having it published.

Ok, so that may be a bit overambitious, especially for someone who's had zero practice in writing fiction for the last 1/4th of his life, but why bother setting goals if you're not going to set them high? My goal is to begin writig in earnest starting no later than November this year, hopefully sooner. Basically, I have a number of consulting projects and training jobs that are cluttering my schedule now, keeping my brain in a very logical, non-fictional world, but come October or November, I'll have those projects wrapped up and I won't be taking on any new ones until I emerge from my writing cocoon. (Granted, I'll still be writing non-fiction articles for 4Guys and, hopefully, MSDN, but I'll have suspended the dozens of hours a week consulting projects consume, and dedicate those to writing.)

The wife is happy to let me try this for a while, so long as there are tangible results. I don't think she'll be too excited to come home from a long day of work after fighting traffic to find me in my bathrobe, unshaven, holding a Big Gulp, reporting, “Today I narrowed down the title to one of three choices.” I already have the germ of the idea for the novel, have had it bouncing around the noggin for the past few months, in fact. It involves computers, surprise, surprise, and therefore will likely be enjoyed by geeks and nerds alike. There will also be plenty of explosions and car chases, if I want someone to ever make it into a movie.

What really piques my interest currently is the economics of writing a novel. I know, firsthand, the depressing economics involved behind writing a computer trade book, and would guess that the same results are experienced by 99% of published fiction writters out there. (Ever notice just how many novels there are in a book store? For every “best seller” by King there are several dozen no-name novels filling the shelves as well.) While this may sound depressing, it does offer some hope that there is a chance, however remote, of actually getting a work I create to press.

Filed under:
Back from the Honeymoon
05 July 04 04:04 PM | Scott Mitchell

My wife and I got back from our honeymoon this weekend. After 13 days of absolutely no computers, no cell phones, no email, and no Internet, I came home to 6,000+ spams. Joy.

The trip was really enjoyable, neither of us had been out of the northwestern hemisphere, so our trip to Europe was most enjoyed. In fact, we were in Amsterdam from June 22nd through June 25th, which coincidentally coincided with TechEd Europe 2004. And no, neither of us are big enough dorks to go to TechEd on our honeymoon. In any event, it was fun to try to pick out what folks wandering around the city were TechEd attendees.

It's good to be back, though, to sleep in our own bed. To use a computer and catch up on email. To see our dog. And on and on. But at the same time I don't know if I'm 100% yet ready to jump back into the swing of things. The trip was very restful and enjoyable, and now I feel a bit spoiled.

In an attempt to keep this entry remotely on topic, I wanted to point out that the cover story in the latest issue of asp.net PRO is an article of mine on displaying content from an RSS syndication feed on an ASP.NET Web site. In the article, which you can read here if you're an asp.net PRO subscriber, I show how to use the XPathNavigator class in the System.Xml namespace to programmatically read and display the contents of an RSS feed in an ASP.NET Web page. I then talk about RssFeed, an open-source compiled server control I created to display RSS feeds on ASP.NET Web pages. In the upcoming August issue of asp.net PRO, I'll have another article on RSS - this next one will illustrate how to syndicate content according to the RSS standard.

And finally, before I close, in case anyone has not yet heard about Beta 1, or the Express versions of Visual Studio 2005, you can learn more at http://lab.msdn.microsoft.com/vs2005/ and http://lab.msdn.microsoft.com/express/.

More Posts

Archives

My Books

  • Teach Yourself ASP.NET 4 in 24 Hours
  • Teach Yourself ASP.NET 3.5 in 24 Hours
  • Teach Yourself ASP.NET 2.0 in 24 Hours
  • ASP.NET Data Web Controls Kick Start
  • ASP.NET: Tips, Tutorials, and Code
  • Designing Active Server Pages
  • Teach Yourself Active Server Pages 3.0 in 21 Days

I am a Microsoft MVP for ASP.NET.

I am an ASPInsider.