October 2008 Blog Posts

After a long-weekend marathon, WHS Disk Management v1.1.0.0 has finally reached alpha status. I'm looking for a few brave souls to help with testing; if you're interested, send me a private message on the We Got Served forums, or contact us using the blog.

So what's new in this release? Well, exciting things are afoot.

We've changed to a client/service architecture, removing the heavy-lifting from the Add-In code and pushing the processing out to a Windows service. The change was made for a number of reasons, the most important of which are:

  1. To follow Microsoft's new developer guidelines for Windows Home Server Add-ins
  2. To remove most of the excuses we had for not developing alerting, logging, and reporting capabilities in the Add-In

We'll be testing this release for a lot longer than we have in the past; this is a significant departure from the previous architecture, and we need to make sure we've got it right.

We promise that the next release will be worth the wait!

The Windows Home Server user interface includes a number of controls that extend normal Windows Forms functionality. FancyListView is the Windows Home Server extension of ListView, and includes a few nifty features:

  • ImageSubItems to display images as ListView subitems
  • FilledBarSubItems to show a configurable progress bar and accompanying label as a subitem
  • Sorting by column works out of the box

Brendan has a lot more detail on these new features in WHS Developer Tip #11: FancyListView.

Dropping a FancyListView on to your design surface and adding a few columns is easy. You can load up ListViewItems and work with the FancyListView as you would a normal ListView, and you don’t need to do any work to implement sorting. It can’t get any more straight-forward, really.

Because FancyListView is based on ListView, you can also use groups. Groups in a ListView help you visually break down items into related sets, for easier identification.

To use groups, you need to instantiate a new ListViewGroup, add the group to the Groups collection of the ListView and then assign the group to the Group property of the ListViewItem.

FancyListView ListViewDisks = new FancyListView();
ListViewGroup GroupStoragePool = new ListViewGroup("Storage Pool");
ListViewItem item = new ListViewItem();

ListViewDisks.Groups.Add(GroupStoragePool);

item.Group = GroupStoragePool;

ListViewDisks.Items.Add(item);

You’ll end up with something like this:

 image

Groups can significantly improve readability of the data in in a ListView with a lot of ListViewItems. The major downside of using Groups with a FancyListView is that they break the built-in column sorting.

If you want to use groups, and continue to sort your FancyListView by column (who doesn’t?), the solution is to implement a custom FancyListViewColumnSorter that handles the sorting for you.

public class ListViewColumnSorter : Microsoft.HomeServer.Controls.ListViewColumnSorter
{
    public override int Compare(object x, object y)
    {
        ListViewItem item1 = (ListViewItem)x;
        ListViewItem item2 = (ListViewItem)y;

        int result = String.Compare(item1.SubItems[SortColumn].Text, item2.SubItems[SortColumn].Text);

        if (Order == SortOrder.Ascending)
        {
            return result;
        }
        else if (Order == SortOrder.Descending)
        {
            return -result;
        }
        else
        {
            return 0;
        }
    }
}

We override the Compare method so we can make our own decisions about how to compare the two ListViewItems.

In the example above, I’m sorting on the Text value, using String.Compare. What if our two text values are “80.0 GB” and “157.0 GB”? Because I’m comparing the string value, “157.0 GB” comes first – probably not the result we want.

To work around this, you could store the unformatted number of bytes (168577466368, for 157 GB) as the SubItem.Tag, and compare that instead. Then our 80 GB drive will be correctly listed first.

Once you’ve customised your FancyListViewColumnSorter , assign is to the FancyListView.

FancyListView ListViewDisks = new FancyListView();
ListViewDisks.ListViewItemSorter = new ListViewColumnSorter();

Add an event handler for the ColumnClicked event of the FancyListView that calls the Sort() method.

private void ListViewDisks_ColumnClick(object sender, ColumnClickEventArgs e)
{
    ((ListViewColumnSorter)this.ListViewDisks.ListViewItemSorter).SortColumn = e.Column;
    ((ListViewColumnSorter)this.ListViewDisks.ListViewItemSorter).Order = SortOrder.Ascending;

    ListViewDisks.BeginUpdate();
    ListViewDisks.Sort();
    ListViewDisks.EndUpdate();
}

You’ll see that I’m calling BeginUpdate() and EndUpdate() on the ListView; this prevents some very odd redraw issues that basically make your FancyListView unreadable.

You can also get creative with the SortOrder by adding some code to reverse the SortOrder when the same column is clicked twice (changing from Ascending to Descending). The variable e.Column is the zero-based index of the column that was clicked, so you can check to see if you’ve passed the same column number to your FancyListViewColumnSorter.SortColumn.

For bonus points, you could create yourself an enum to keep track of which columns are which.

public enum ListViewColumns
{
    PhysicalDisk = 0,
    Interface = 1,
    DiskController = 2,
    Location = 3,
    DiskName = 4,
    Capacity = 5,
    Used = 6,
    Status = 7,
    Temperature = 8,
    Activity = 9
}

Each of those columns could have its own sorting criteria, and you can handle that in your FancyListViewColumnSorter.

public class ListViewColumnSorter : Microsoft.HomeServer.Controls.ListViewColumnSorter
{
    public override int Compare(object x, object y)
    {
        ListViewItem item1 = (ListViewItem)x;
        ListViewItem item2 = (ListViewItem)y;

        int result = 0;

        switch ((ListViewColumns)SortColumn)
        {
            case ListViewColumns.PhysicalDisk:
                result = ((int)item1.Tag).CompareTo((int)item2.Tag);
                break;
            case ListViewColumns.Used:
                result = ((FancyListView.FilledBarSubItem)item1.SubItems[SortColumn]).PercentageFilled.CompareTo(((FancyListView.FilledBarSubItem)item2.SubItems[SortColumn]).PercentageFilled);
                break;
            case ListViewColumns.Capacity:
                result = ((long)item1.SubItems[SortColumn].Tag).CompareTo((long)item2.SubItems[SortColumn].Tag);
                break;
            case ListViewColumns.Temperature:
                result = ((int)item1.SubItems[SortColumn].Tag).CompareTo((int)item2.SubItems[SortColumn].Tag);
                break;
            case ListViewColumns.Activity:
                result = ((float)item1.SubItems[SortColumn].Tag).CompareTo((float)item2.SubItems[SortColumn].Tag);
                break;
            case ListViewColumns.Interface:
            case ListViewColumns.DiskController:
            case ListViewColumns.Location:
            case ListViewColumns.DiskName:
            case ListViewColumns.Status:
            default:
                result = String.Compare(item1.SubItems[SortColumn].Text, item2.SubItems[SortColumn].Text);
                break;
        }

        if (Order == SortOrder.Ascending)
        {
            return result;
        }
        else if (Order == SortOrder.Descending)
        {
            return -result;
        }
        else
        {
            return 0;
        }
    }
}

Not every FancyListView will need that sort of complexity, of course, and you’re making an assumption that only the FancyListView with those precise columns will every be using this FancyListViewColumnSorter.

On the other hand, having the capability to customise a Sorter to your exact requirements does give you a lot of flexibility.

MVP_BlueOnly From the ‘Entirely Unexpected But Definitely Awesome’ department comes an MVP award from Microsoft, for my development work with Windows Home Server. I’m now amongst such illustrious luminaries as Terry, Phil, and Ken Warren.

Between you and me, I almost deleted the welcome email as spam.

Now, of course, I have to live up to the hype. I’ve mostly been posting on the We Got Served forums, and occasionally on the Windows Home Server Microsoft Forum, so I haven’t had a central place from which to pontificate about Windows Home Server development topics.

Good excuse for a developer blog, right?

Plus, I should really have a place to talk about tentacleSoftware, our products, and our plans for world domination. We’ve had quite a bit of success with WHS Disk Management, and we plan to continue that with more releases in the future (for Windows Home Server and other platforms).

So, stay tuned for more goodies. We have some secret plans, and clever tricks, in the works that I think Windows Home Server users will be very, very excited about.

Search

Site Sections

Recent Posts

Archives

Post Categories

WHS Add-In Tutorial

WHS Blogs

WHS Development