Wednesday, April 22, 2009

Internet Explorer 7, Print Preview Page Generator


I found a bug (or at least what I think is a bug in Internet Explorer 7.  Here’s the scoop: when you print preview a page in IE7, you get a nice little popup of the page(s) and how it will print.  Great.  Well depending on how the page is created, it might not work.  Down at the bottom of the preview it gives you a “Page 1 of X” (where X is the total number of pages).  As you can see from the image, the number of pages is 2076, but what you cannot see is that it is still increasing…  doh! 

Under certain circumstances you can make the function that calculates the total number of pages to print to “freak out” or rather infinitely loop, thus never displaying the actual preview of the page.  This is only an issue in IE7.  The same test works fine in Firefox 2.0.0.6.  I have not yet tested it in any other browser or version of a browser.

 

I have not completely narrowed down the issue yet either.  But I have found that if you use DIV tags and a CSS style sheets to layout your pages, you may come across this issue.  Some facts: this page is built dynamically.  My div tags are all fixed width.  There are nested div elements up to 3 or 4 levels, and there are label elements with empty “for” attributes.  All the layout is done using the style sheet and div attributes.  The interesting thing is that this issue only happens on pages that are longer than about 2 print preview pages; which means that it seems to either be the data in the elements, or the number of elements on the page. 

 

First, I made sure that all my tags had appropriate closing tags and formatting (text case and all that).  I threw it into Visual Studio 8 and formatted and validated the text.  Same issue.  Next, I started from the bottom of the page and started commenting out the div blocks one by one and testing the print preview after each.  After commenting out two of them, the issue went away and the print preview displayed fine.  So I thought there must be something wrong with one of these divs.  Turns out that there is nothing wrong with them.  I found that I could uncomment those divs and comment out the first few divs and the problem would also be resolved.  So then I uncommented all the divs again (essentially restoring the problem), and removed the CSS stylesheet reference.  Again the problem went away.

 

Okay, now this is messin’ with my brain…. 

 

So ultimately, I submitted the issue to Microsoft.  Right now, this currently looks like a bug.  I found the following article on MSDN: http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/5defae18-1e29-4f75-a47c-670c82ab15de and submitted my issue there.  The original issue was reported in 2008, so I’m not sure if anyone is still tracking the problems.  If you have any solutions to this issue please post your comments here.  I still need to resolve this issue.  Thanks!


The problem is resolved in the latest version of Internet Explorer 8.

Wednesday, April 1, 2009

How to Speed Up Finding an Element in a System.Collection.IList

I've been working on a program for some time now that I inherited. It's a great program, most of the code is designed well, but some of the implementations of the design have been less than desirable, especially when you are talking about speed. Let me explain:

I've recently found a bottleneck in some of the code I've been optimizing. For instance, I have a System.Collection.IList that is basically given to me to use (since it has been implemented using a third party tool, the trade-off for removing it was not an option). I don't recall what the IList was implemented as, but the IList does not allow me to call a List.Contains(object value), or List.IndexOf(object value). If it did, I would not be in the situation I am. The bottom line is that I needed to have an implementation of the .Contains() and .IndexOf() methods. So here's how it was implemented:

public bool Contains(Guid _reviewAnswerId)
{
int listCount = myList.Count;
for (int i = 0; i < listCount; i++)
{
if (myList[i].ReviewAnswerId.Equals(_reviewAnswerId))
return true
}
return false;
}


public int IndexOf(Guid _reviewAnswerId)
{
int listCount = myList.Count;
for (int i = 0; i < listCount; i++)
{
if (myList[i].ReviewAnswerId.Equals(_reviewAnswerId))
return i;
}
return -1;
}


As you can see from the code above, the way you find a match is to loop through each object (I could have used a foreach statement, but I was trying to optimize and a for loop helped slightly) and match the value. If a match is found then "true" is returned and if not then "false" is returned for the Contains() method. For the IndexOf() method, you are looking for the index where the object resides in the IList, so you can reference it in some other place of the code.

So this is all fine and dandy if your collection is garanteed to stay small (which was the intention of the collection at design time). This method of search is a linear search, O(n). But you'll see that its actually O(n^3). Since then, the design has been extended to allow the collection to contain upwards of 5000 objects (which really is not that many, so I thought). It turns out, that these objects have multiple data elements, and everytime the object was referenced it would take a very long time to check (I found it by pausing the debugger when the program was halted for the time it was performing this routine). This looping and checking would not be performed once, but between 2000 to 4000 times, and that would be performed 400 to 800 times, so the number of times the list is accessed would be more like 800 * 4000 * 5000 = 16,000,000,000 billion times. OUCH!

So there are a few things that I did to fix the search time. First of all, where I could, I pulled all the direct calls to the object ("List[i]") into a local variable to reduce the overhead of those calls (though this did not do much). Second, I implemented a System.Collections.Hashtable that was pretty much a clone of the IList (a clone of the objects and the number of objects, not the order they are stored). Hashtables are typically O(1). Which means that you'll find you value a heck of a lot faster than a linear search. So each time I add an object to the IList, I add the same object to the Hashtable, and the same goes for removing objects. I then changed the Contains() method to the following:

public bool Contains(Guid _reviewAnswerId)
{
return _hashTable.ContainsKey(_reviewAnswerId);
}


The IndexOf() method then goes away, since you can then reference the object in the following manner:

return (CastToMyObject)(_hashTable[_reviewAnswerId]);

BINGO! Problem solved.