April 2007 Archives

I added 4 new samples to the current Crystal Toolkit 0.75 release, and cleaned up some of the old ones. First of all, I think it's important when users open a toolkit that they can see some sample programs right off the bat without compiling the code. I've placed a bin folder under the root Attilan, which contains the CrystalToolkit.dll and the sample programs. If you click on StartDemo.bat under Attilan or CrystalDemoLauncher under Attilan\bin, you will see the CrystalDemoLauncher program:

Demo Launcher with Crystal Panel

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:

SimpleImageGrid Demo with Roxy

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:

Wait Form with Picture Show 1

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:

Wait Form with Picture Show 2

There you have it. I thnk this could be a nice wait dialog with regular photograph thumbnails if you chose to do so. Download the free Crystal Toolkit 0.75 if you want to try this kind of wackiness.

Crystal Toolkit is a Windows Forms (.NET Framework 2.0) control library written in C#. This is the seventh release and contains the following updates:

Enhancements.

  1. CrystalCollector: AddImage and AddImageItem methods allow you to add images without calling CollectImages and having it auto-magically thumbnail images. In using these methods, you pay a price in having to setup things correctly. See the demo program BorderSplitMode for more details about how this is used with CrystalMemoryCollector.

Demo Programs Expanded.

  1. Demo Launcher program starts all demos. Click on "StartDemo.bat" in the root Attilan folder or CrystalDemoLauncher.exe in Attilan\bin.

  2. Simple Image Grid Demo: A simple illustration of how to use CrystalImageGridView with the CrystalFileCollector to thumbnail disk-based images in a background thread.

  3. BorderSplitMode Demo: Use CrystalImageGridView and a derived Collector to assign each image item its own border color, as I explained here in this article.

  4. CrystalPictureBox Demo: Use CrystalPictureBox to display scrollable or ratio-stretched images.

  5. CrystalPictureShow Demo: Use CrystalImageGridView to navigate thumbnail images and then use CrystalPictureShow to display them and perform Slideshows.

  6. WaitForm PictureShow Demo: Use CrystalPictureShow to create a unique wait dialog.

Bug fixes.

  1. CrystalTrackBar: SmallChange and LargeChange were implemented. Control was not behaving properly when nested inside a container like a Panel or GroupBox. I also fixed a bug where the thumb was not able to move between ticks, if you were going from 0 to 10, it would skip to 10. Now it will go 0, 1, 2, 3...10. In fixing CrystalTrackBar, I decided to prohibit TransparentMode. It wasn't working very well. I had no intention of making a TrackBar replacement, my goal was just to get a TrackBar on a ToolStrip. I've taken my old implementation of CrystalTrackBar and placed this into CrystalFixedTrackBar, which is used only by CrystalToolStripTrackBar. I'm afraid the TrackBar component will never be a full replacement in either case, but it works well enough in my Image Viewer application that I'm happy with it.

  2. CrystalImageGridView: UseAlpha was set to true by default. This is now set to false by default.

  3. CrystalComicShow: Normal "non-comic CDisplay" images were incorrectly displayed when going back using the left arrow key.

This release comes in a ZIP file. Simply unzip the contents to your hard drive, navigate to the root Attilan folder, and double click on CrystalDemo.sln. This solution file contains the Crystal Toolkit plus demo programs. Just build the solution (which compiles the CrystalToolkit library first) and run the demo programs to see how they work. You can run the demo programs without building the source by clicking on "StartDemo.bat" in the root Attilan folder or CrystalDemoLauncher.exe in Attilan\bin.

I've tested the demos under Windows XP SP2 and Windows Vista. Needless to say, buyers beware, this is alpha software and it's free open-source code: you get what you pay for! I'd welcome any feedback, bugs (or bug fixes), and thumb-bitmap replacements. Send email to richard [at] attilan {dot} com.

Download: Crystal Toolkit 075 (zip file, 4.2 mb)

By default, CrystalImageGridView allows you to display thumbnail images with a single border color (CellBorderColor property) that is displayed whenever the CrystalImageItem is selected. That's standard behavior, but a few months ago, I ran into a situation where I wanted to indicate a state for particular image items in the grid. At the time, the best way to handle was to give each CrystalImageItem a unique border color that could be displayed permanently, regardless of selection state. As a result, a range of items could have a red border, others could have a green border. You can create your own customized Collector object to assign these border colors. If you look at this example, I created a subclass from CrystalFileCollector and assigned border colors after all the Images were collected:

public class MyCollector : CrystalFileCollector
{
    public override bool CollectImages()
    {
        bool result = base.CollectImages();

        if (result)
        {
            int index = 0;
            foreach (CrystalImageItem imageItem in GridModel)
            {
                index++;
                if ((index % 2) == 0)
                {
                    imageItem.BorderColor = Color.Red;
                }

                if ((index % 3) == 0)
                {
                    imageItem.BorderColor = Color.Green;
                }
            }
        }

        return result;
    }
}

That's kind of a cheesy example. You might want to examine the Tag property of CrystalImageItem, where you can store your own objects during the collection phase. However, for this simple example, it results in CrystalImageGridViewer displayed the following images with permanent border colors:

BorderSplitMode

That looks fine, but what happens when the images are selected? There's a new property which determines the selected border color in this special mode. The selected border color gets drawn inside the state border color. This is so the user can see that the image item is selected, but also recognize the status of the item. Here's what it looks like when the selected border color is set to Black:

BorderSplitMode Selection Color

Achieving this in your own programs is easy. You will need to change a few properties in CrystalImageGridView in the Forms Designer within Visual Studio:

BorderSplitMode Properties

  1. Set BorderSplitMode to True.

  2. Set CellBorderColor to Transparent. (You will assign border colors programmatically through CrystalImageItem's BorderColor property.)

  3. Set CellSplitColor to whatever you like for the inner selection border color.

  4. Make sure BorderWidth is large enough. The inner and outer borders split this width, with the inner border taking up 1/3 of the size.

In the next release of the toolkit, I will have a sample program that demonstrates this feature.

One of the things I wanted to achieve in Crystal Toolkit release 74 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.

Crystal Toolkit is a Windows Forms (.NET Framework 2.0) control library written in C#. This is the seventh release and contains updates for the following classes:

New in 0.74: Features.

New controls: CrystalComicShow.

New controllers for images: CrystalMemoryCollector, CrystalZipCollector, CrystalRarCollector.

New controller options: SortCrystalList method and CrystalSortType enumerator.

New slideshow options: Shuffle and Repeat modes were added. Slideshow options are now in CrystalSlideShowOptions, which will break older Form applications using the previous build.

  • CrystalComicShow: A subclass of CrystalPictureShow. A control that display comic-book images from CDisplay archive files. You can access CBR and CBZ files and see the thumbnailed images just like any picture folder. No sample for this yet--it's part of the main application I'm working on for a free release later this year.
  • CrystalMemoryCollector: I needed a collector that didn't work off any disk-based files whatsoever. This class needs to be fleshed out a bit more, but I intend to write a nice sample that shows how you can build a cool wait dialog using this controller.
  • CrystalZipCollector: This was built for CrystalComicShow, to enable me to display comic book images from a CBZ (zip) file. It may have broader applications. It uses ICSharpCode.SharpZipLib.dll, which is included in the open_source_code folder of CrystalToolkit. You can download the full version of SharpZipLib here.
  • CrystalRarCollector: This was built for CrystalComicShow, to enable me to display comic book images from a CBR (rar) file. It may have broader applications. It uses unrar.cs, which is included in the open_source_code folder of CrystalToolkit. To make this work with your application, you must include unrar.dll in your application folder. You can download unrar.cs and unrar.dll from RARLab.
  • Controller sorting: CrystalFileCollector now contains a public method called SortCrystalList. This takes an enum called CrystalSortType and allows you to sort on ImageName, ImageType, CreationDate or LastWriteTime. You can sort using this type in either ascending or descending order.
  • Slideshow enhancments: The Slideshow options were taken out of CrystalPictureShow as individual properties. They are now contained with the object CrystalSlideShowOptions, which is a new property within CrystalPictureShow. Shuffle and Repeat modes were added to the slideshow options. You can also begin a slideshow at any starting position within the current CrystalCollector.
  • To see how to build a C# image viewer with thumbnails slideshow application: Download the zip file in the link below and unzip to your hard drive. Navigate to the Attilan folder. Double click on CrystalDemo.sln. Hit F5 to build CrystalToolkit and execute the demo program, CrystalImageGridDemo.

This release comes in a ZIP file. Simply unzip the contents to your hard drive, navigate to the root Attilan folder, and double click on CrystalDemo.sln. This solution file contains the Crystal Toolkit plus demo programs. Just build the solution (which compiles the CrystalToolkit library first) and run the demo programs to see how they work.

I've tested the demos under Windows XP SP2 and Windows Vista. Needless to say, buyers beware, this is alpha software and it's free open-source code: you get what you pay for! I'd welcome any feedback, bugs (or bug fixes), and thumb-bitmap replacements. Send email to richard [at] attilan {dot} com.

Download: Crystal Toolkit 074 (zip file, 1.9mb)