Pulled Apart - Part XIV: DevExpress

Note: This is part of a series, you can find the rest of the parts in the series index.

I make no attempt to hide my love for a company called DevExpress, which produces enhancements for Visual Studio and additional controls for WinForms, ASP.NET Web Forms, ASP.NET MVC, WPF, and Silverlight.

When I started with Pull, I used mostly the standard WinForms controls, but over time changed it to be almost 100% DevExpress controls for a number of reasons:

Below is the first public version of Pull, which uses only DevExpress GroupBoxes, while the rest is all WinForms:

image

versus the UI currently in development (for the January 2011 release), where only the status bar and web browser control are not from DevExpress! I think you’ll agree it looks way better now, plus there are many new features there—like filtering grids—which weren’t supported previously.

image

Grid Extensions

For the January 2011 release, we switched to DevExpress grids, which meant a lot of code needed to be changed (or deleted). I ended up writing a few extensions for the grids that I believe may be useful to others:

Return a collection of selected items

Instead of working with a collection of selected rows, this lets you get the values of the selected rows:

public static IEnumerable<T> SelectedItems<T>(this ColumnView view) where T : class
{
    foreach (int selectedRowHandle in view.GetSelectedRows())
    {
        T item = view.GetRow(selectedRowHandle) as T;
        yield return item;
    }
}

Select a collection of items

The grid normally allows you to select a single row or a continuous range. However, often I want to provide a list of item values and have the rows matching those values selected:

public static void SelectRows<T>(this GridView view, IList<T> selectedItems) where T : class
{
    foreach (T selectedItem in selectedItems)
    {
        for (int counter = 0; counter < view.DataRowCount; counter++)
        {
            T item = view.GetRow(counter) as T;
            if (item == selectedItem)
            {
                view.SelectRow(counter);
            }
        }
    }
}

Layouts and Strings

You can persist the layout of a grid to a stream, the registry, or an XML file. However, I have a settings file and would like to save and restore the layout from strings so I can easily add it to my settings file:

public static string SaveLayoutToString(this GridView view)
{
    MemoryStream gridStream = new MemoryStream();
    view.SaveLayoutToStream(gridStream, OptionsLayoutBase.FullLayout);
    gridStream.Position = 0;
    using (StreamReader reader = new StreamReader(gridStream))
    {
        return reader.ReadToEnd();
    }
}

public static void RestoreLayoutFromString(this GridView view, string layout)
{
    if (!string.IsNullOrWhiteSpace(layout))
    {
        using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(layout)))
        {
            stream.Position = 0;
            view.RestoreLayoutFromStream(stream, OptionsLayoutBase.FullLayout);
        }
    }
}

Enum + Grid + Images = Headache

imageI have an enum for the podcast state and, rather than show the text—which is the default—I want to show an image in the cell. However, this isn’t the easiest thing to figure out, as there’s no designer support for this 🙁. However, you can do most of this in the designer and then only need one line of code per enum value 😊.

Step 1

Set the Column Edit property of the column to an ImageComboBoxEdit: image

Step 2

On the ImageComboBoxEdit editor settings, set the small images (and/or large images) property to the image list containing the items you want to show. It’s important to know the position (or index) of the image in the image list.

Step 3

Now, all you need to do is add the item values for the editor in code using the _Items.Add method, which takes an ImageComboBoxItem. That class has overloads that accept an Object for the value, and here you can put in the enum value. Once this is done, it all works fantastically.

You’ll note in the demo code below that I have an image index of -1 for the first item—that’s so no image is shown!

editor.Items.Add(new ImageComboBoxItem("None", PodcastState.None, -1));
editor.Items.Add(new ImageComboBoxItem("Downloading", PodcastState.Downloading, 0));
editor.Items.Add(new ImageComboBoxItem("Pending", PodcastState.Pending, 1));
editor.Items.Add(new ImageComboBoxItem("New Episodes", PodcastState.NewEpisodes, 3));
editor.Items.Add(new ImageComboBoxItem("Error", PodcastState.Error, 2));