Saturday, April 21, 2007
Crystal Image Toolkit for C# Windows Forms: New Samples Illustrate How to Create Image Grid Viewers
The gradient background in the demo launcher is provided by CrystalPanel. I've been using this in many applications and it always helps make a Windows Forms program a bit more attractive. I think it looks even better when paired with the KryptonLabel and KryptonLinkLabel controls at Component Factory.
I wanted to provide a minimal program that shows how CrystalImageGridView works. The SimpleImageGridView demo program has about 140 lines of code in Form1.cs. This sample merely looks at your MyPictures folder and thumbnails all the images within it. If you have no images, click on File\Open Folder menu item and select another folder. Here's an example of how it looks--and hold on to your hat--I am going to show you images from actual photographs instead of comic books:
This is our part-time labrador-mix, Roxie the Rocket dog. We take care of her when our friends are out of town. We love this dog, but it's the perfect situation because we get to take care of her and we get our own time as well.
I can't just leave this article without doing something comic-book related. Here's a Form that I recently implemented as a demo called WaitFormPictureShow. It's one of those "watch-me-spin while-you-wait" dialog/forms that you look at while the program is processing something. It does use a wonderful loading circle animation control written by Martin Gagne--download it here on CodeProject. But in addition to that, there is a postage-stamp sized CrystalPictureShow control displaying images in a Fade Slideshow. I loaded up the images into CrystalMemoryCollector, from a project resource file filled with images from Marvel Value Stamps and DC Comics US Postage Stamps:
The CrystalMemoryCollector loads both the full scale image and the thumbnail image--in this case, the same thing. CrystalPictureShow takes the CrystalMemoryCollector (not knowing anything special about it, other than it is derived from CrystalCollector) and displays the Slideshow using the Fade effect. In the code I've told the CrystalPictureShow object not to use its own thumbnailer, as the memory collector has everything loaded and ready to go:
There you have it. I thnk this could be a nice wait dialog with regular photograph thumbnails if you chose to do so.
Download: Crystal Image Toolkit 1.0 from Google Docs.
Tuesday, April 17, 2007
C# Dynamic Sorting for Lazy Programmers
One of the things I wanted to achieve in the Crystal Toolkit's Image collection was the ability to sort my generic List<> of images (CrystalImageItem objects). I needed to be able to sort on many different properties within CrystalImageItem, and also to sort in ascending or descending order. Realizing that I probably needed to implement IComparer and IComparable, I decided that was way too much work, and my XBox Achivements score is really ridiculously low. A Google search on the topic lead me to this CodeProject article by Johannes Hansen on Dynamic List sorting. I found his approach intriguing, because he uses Reflection to key on properties within an object and use them as the basis for a compare operation. The resulting sort times are impressive, though I saw a couple of glitches reported on the CodeProject message board. Luckily, another programmer (Marc Brooks) took up the baton and released a C# library that includes a new, improved DynamicComparer. I highly recommend downloading Marc's library as it contains some nifty C# utilities.
Getting DynamicComparer to work was very easy. First, I had to make sure that the properties within the CrystalImageItem object were public, so that Reflection could find them. No problem there, I had four properties, two strings and two dates within CrystalImageItem:
public class CrystalImageItem { public string ImageName ... public string ImageFormatString ... public DateTime LastWriteTime ... public DateTime CreationTime ...
To make it convenient to specify which property I wanted to sort, I created an enumerator called CrystalSortType:
public enum CrystalSortType { ImageName = 0, ImageType = 1, CreationTime = 2, LastWriteTime = 3 }
The CrystalFileCollector is the controller class that manages a CrystalImageGridView and a CrystalImageGridModel. I created a public method called SortCrystalList, which takes a CrystalSortType enumerator, a boolean to indicate ascending or descending sort, and a boolean that tells the controller to redraw the grid (inside CrystalImageGridView) when the sort is completed:
public virtual void SortCrystalList(CrystalSortType sortType, bool ascendingOrder, bool reDrawGrid)
The protected SortCrystalList method translates the enumerator key to a string and calls a final overloaded method:
protected virtual void SortCrystalList(CrystalSortType sortType, bool ascendingOrder) { string orderBy = string.Empty; switch (sortType) { case CrystalSortType.ImageName: orderBy = "ImageName"; break; case CrystalSortType.ImageType: orderBy = "ImageFormatString"; break; case CrystalSortType.CreationTime: orderBy = "CreationTime"; break; case CrystalSortType.LastWriteTime: orderBy = "LastWriteTime"; break; } SortCrystalList(orderBy, ascendingOrder); }
The last version of SortCrystalList takes the string key, adds either ASC or DESC to the string (for ascending or descending sort) and creates the DynamicComparer. The List<CrystalImageItem> object inside the GridModel is sorted according to this key:
protected virtual void SortCrystalList(string orderBy, bool ascendingOrder) { if (_gridModel == null) return; if (ascendingOrder) orderBy += " ASC"; else orderBy += " DESC"; // Create the comparer for Person types and define // the sort fields. DynamicComparer<CrystalImageItem> comparer = new DynamicComparer<CrystalImageItem>(orderBy); // Sort the list. _gridModel.CrystalImageList.Sort(comparer.Compare); }
By default, CrystalFileCollector sorts the internal list by the ImageName property in CrystalImageItem. When the dynamic comparer object is created, the orderBy key looks like "ImageName ASC". If you read Johannes article, you will see that properties can be combined for more interesting sorts like "FirstName, LastName ASC". This is rather like doing a query on your objects, and so far the performance has been really good. You can naturally see that the Linq Project is going to make this sort of thing obsolete, but kudos to Johannes for coming up with this way back in December 2005.



