Developer Blog
Articles about Using Microsoft Developer Tools

Good Bye IE6—And Good Riddance!

Monday, January 26, 2009 10:18 AM by jonwood

Well, that’s it as far as I’m concerned. I have a laptop that runs Windows XP and, until today, Internet Explorer version 6. However, Windows Update is now automatically updating XP systems to Internet Explorer version 7, which I’ve just installed.

I can only assume Windows Update is doing this now due to recent security holes found in IE6. After being infected with a major virus recently, upgrading to IE7 seemed like a good idea. But as an ASP.NET developer, there are far larger considerations involved.

Internet Explorer 6 is notorious for not following the established Web standards that pretty much every other browser is following. In my view, this has made Website development, particularly layout and CSS, an absolutely nightmare! There have been many times I’ve spent hours getting layout exactly as I want it only to find it does not appear as expected in IE6. In fact, many books I have on CSS design have entire chapters devoted to IE6 and its unique set of layout quirks.

As with most of their products, Microsoft wanted to make their browser exceptional by doing their own thing. But this just doesn’t work in the browser world. There have to be standards in order for the largest number of browsers to work with the largest number of Websites. That’s not to say all other browsers are identical in their rendering of Web content—they’re not. But IE6 was the odd one out with a large majority of issues.

So, until now, I’ve continued to maintain a computer running IE6 in order to be able to test my sites with this browser. But now that Windows Update is urging users to upgrade, I’m going to give up on this browser. Of course, not everyone will upgrade. There are always users who will resist changes like this for as long as possible. But I expect this development to mean that the number of IE6 users will drop significantly. And I’m willing to take advantage of this and no longer work to ensure my sites appear correctly for the diminishing number of users who use this browser.

With IE6 out of the picture, the biggest offender of not following Web standards is now IE7. But IE7 is quite a bit better than IE6. And, perhaps more significant, IE8 is about to be released. IE8 presented Microsoft with some difficult decisions. On the one hand, Microsoft realized that the latest Web standards could no longer be ignored. But on the other hand, if they came out with a fully compliant browser, they would break compatibility with previous versions, causing some pages that looked fine with IE6 to no longer appear correctly.

There was considerable discussions about whether IE8 should require a flag in the HTML code to tell it to use the new compliant mode, otherwise, it would default to being compatible with prior versions. This would allow both new and old sites to appear correctly.

I fought strongly against this approach. This opens up a whole can of worms. And, from a Web developer’s viewpoint, it’s critical to get everyone in line using the current standards and end the chaos we have now, which was caused in large part by the noncompliance of IE6. Although I have not played with IE8 or heard the latest on this issue, I did hear at one point that the decision was to make IE8 standards-compliant by default.

If this becomes the final decision, I applaud Microsoft for making this hard choice. They will take a hit if they come out with a browser that, by default, produces different rendering of some Web pages than previous versions of IE. But I think this is in the best interest the industry. And, in my book, not having to worry about IE6 anymore is a good thing.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   ASP.NET
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Implementing Non-ASP.NET Posts in ASP.NET

Thursday, January 22, 2009 6:14 AM by jonwood

When interfacing with some resource on the Web, you are sometimes provided with a little snippet of HTML code. For example, to insert a PayPal button on your Website, PayPal provides HTML code that may look something like this.

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
  <input type="hidden" name="cmd" value="_xclick">
  <input type="hidden" name="business" value="bob@domain.com">
  <input type="hidden" name="lc" value="US">
  <input type="hidden" name="item_name" value="Widget">
  <input type="hidden" name="amount" value="100.00">
  <input type="hidden" name="currency_code" value="USD">
  <input type="hidden" name="bn"
    value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
  <input type="image"
    src="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
    border="0" name="submit" alt="">
  <img alt="" border="0"
    src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1"
    height="1">
</form>

HTML code to insert PayPal button

This snippet defines a <form> and several <input> tags, including a submit button. When the submit button is clicked, the items in the form are posted to the URL specified in the action attribute of the <form> tag. The target URL can then inspect the values of those <input> tags and perform the required operation.

However, you may find that such snippets don’t work correctly when inserted into an ASP.NET page. The main problem is that ASP.NET pages already define a form. In order for ASP.NET’s post-back mechanism to work, all the controls are placed within a <form> tag. Since HTML doesn’t allow nested <form> tags, inserting code like that shown above into an ASP.NET page causes problems.

There are a number of possible approaches to resolving this. Let me start with a couple that I think are less than ideal. The first approach is to simply move the inserted HTML code after the ending </form> tag of the ASP.NET form. Although you cannot nest <form> tags, it is okay to include multiple, non-nested <form> tags on the same page.

The result of this is that the page now has two separate <form> tags and you’ll find this generally works as expected. However, the problem here is that you lose some ASP.NET functionality. For example, the inserted HTML code comes after your ASP.NET form and so it is not really embedded within your ASP.NET content. And if you are using master pages, you cannot do this in content pages because everything in a content page is placed inside of the <form> tag defined in the master page.

The second approach is kind of an ugly hack and is shown below.

protected void btnPayPal_Click(object sender, ImageClickEventArgs e)
{
  System.Web.HttpContext.Current.Response.Clear();
  System.Web.HttpContext.Current.Response.Write("<html><head>");
  System.Web.HttpContext.Current.Response.Write(
    "</head><body onload='document.form1.submit()'>");
  System.Web.HttpContext.Current.Response.Write(
    "<form action='https://www.paypal.com/cgi-bin/webscr' " +
    "name='form1' method='post'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='cmd' value='_xclick'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='business' " +
    "value='bob@domain.com'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='lc' value='US'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='item_name' value='Widget'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='amount' value='100.00'>");
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='currency_code' value='USD'>
  System.Web.HttpContext.Current.Response.Write(
    "<input type='hidden' name='bn' " +
    "value='PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest'>
  System.Web.HttpContext.Current.Response.Write(
    "<input type='image' " +
    "src='https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif' " +
    "border='0' name='submit' alt=''>");
  System.Web.HttpContext.Current.Response.Write(
    "<img alt='' border='0' " +
    "src='https://www.paypal.com/en_US/i/scr/pixel.gif' " +
    "width='1' height='1'>");
  System.Web.HttpContext.Current.Response.Write("</form>");
  System.Web.HttpContext.Current.Response.Write("</body></html>");
  System.Web.HttpContext.Current.Response.End();
}

Ugly hack to perform non-ASP.NET postback

This code runs in response to the user clicking a button named btnPayPal. It dynamically creates an HTML page and then serves it to the user’s browser. The page created duplicates the form in our first listing but adds an onload attribute to the page’s <body> tag that causes the form to be submitted as soon as it loads and the user never sees this temporary page.

This is definitely an ugly hack. And, while it works, it has some problems. The main problem is if, after running the code, the user presses the Back button in their browser, the browser will reload this temporary page, which will cause the same action to happen again, which definitely has the potential to cause some nasty problems.

After exploring both of these options, I finally settled on a third approach that seems more straight forward and doesn’t seem to have any major problems. Beginning with ASP.NET 2.0, buttons have a property called PostBackUrl, which can be used to have that button post back to a page other than the page that contains the button.

At first glance, this didn’t seem helpful. ASP.NET buttons are designed to post back to ASP.NET pages. And I wanted to post back to an non-ASP.NET page. However, the post-back mechanism is the same in both cases. If we post back to a non-ASP.NET page, we’re going to send a lot of additional data—all of the form items on our ASP.NET form—to the target page. But, as long as their is no conflicting item names, which is unlikely, this really isn’t a problem.

Armed with this knowledge then, we can rewrite our original code block and insert it into an ASP.NET page.

<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="bob@domain.com">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="Widget">
<input type="hidden" name="amount" value="100.00">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn"
  value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
<asp:ImageButton ID="ImageButton1" runat="server"
  ImageUrl="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
  PostBackUrl="https://www.paypal.com/cgi-bin/webscr" />

PayPal button inserted into ASP.NET page

I’ve removed the <form> tag from this code. We don’t need it since our ASP.NET form already defines a <form> tag. I’ve removed the <img> and submit <input> tags and I’ve replaced them with an ImageButton. I set the ImageButton’s ImageUrl property to the same PayPal button image used in the original code and, finally, I set the PostBackUrl property to the URL specified in the action attribute of the <form> tag in our original HTML code.

The result is that, when the ImageButton is clicked, the entire form is posted to the PayPal URL. As I mentioned before, this includes all our other ASP.NET values, including the page’s ViewState data. But the ViewState data is encrypted and the PayPal site will only look at those values it is interested in.

The result is that I’ve inserted a PayPal button at any location within my ASP.NET form, I’m still able to make use of all ASP.NET features, PayPal gets all the values it needs to do its job, and there is no funny business if the user happens to hit the browser’s Back button from the PayPal site.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:   ,
Categories:   ASP.NET
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Selecting a ListView Item

Thursday, January 08, 2009 5:03 AM by jonwood

Recently, I was writing a C# desktop application that processed records from a database. I wanted to provide visual feedback as to what was going on so I decided to add each record to a ListView control as the record was processed.

In order to highlight the current item, and also to scroll the ListView control as needed in order to keep the current item visible, I decided to select each item after I added it to the list.

I was surprised to find that there is no single method that will select an item as though it was clicked with the mouse. You can select an item by setting it's Selected property to true. But the ListView control allows multiple items to be selected and so selecting an item does not unselect any already selected items.

Also, when you click on a ListView item, it also gets a focus rectangle drawn around it. This is a type of dotted line that shows which item is the current item. (Note that the focus rectangle is only drawn when the control itself has the focus.)

And finally, when you click on a ListView item with the mouse, the ListView will scroll, if needed, so that the newly selected item is fully visible within the ListView’s client window area.

As I mentioned, there is no single method to duplicate all the actions that occur when you click on a ListView item with the mouse. The code I ended up with to add an item to a ListView control and fully select that item is shown in Listing 1.

ListViewItem item = new ListViewItem();
lvwInfo.SelectedItems.Clear();
lvwInfo.Items.Add(item);
lvwInfo.EnsureVisible(item.Index);
item.Selected = true;
item.Focused = true;

Listing 1: Adding, and then selecting a ListView item as though it had been clicked with the mouse.

I don’t understand why a higher level method is not provided to accomplish this same task. Not only would that save the time required to find all the individual methods required to accomplish this, but it’s possible that the control could change in the future to require an additional or different step. Having this logic as part of a single method in the control allows the control developers to make changes as needed and all code that uses that control would then work correctly.

Currently rated 3.0 by 2 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   C# .NET
Actions:   E-mail | del.icio.us | Permalink | Comments (2) | Comment RSSRSS comment feed