.comment-link {margin-left:.6em;}

I Hate Linux

Monday, December 31, 2007

WHS Developer Tip #13: MessageListBox

Q: How can I create my own list like what I see in the Home Server Console's Network Health dialog?

A: Another one of the custom ListBox (like) controls exposed by Windows Home Server is the MessageListBox control, the very control that is used to display network health messages as well as the installed and available add-ins:

Home Network Health

Like so many other controls, in order to use it we need only drag an instance from the toolbox to our form or control in the designer... but it is here where the simplicity ends.

While called a ListBox... MessageListBox inherits from the Panel class and offers only a few extra enhancements over it... the most notable being the Items field which is the collection of MessageListBoxItem instances which correspond to the visual items we see.

In order to add new items to the list, it can be as simple as:

MessageListBoxItem redItem = new MessageListBoxItem(Color.Red);
messageListBox1.Items.Add(redItem); 
 
MessageListBoxItem yellowItem = new MessageListBoxItem(Color.Yellow);
messageListBox1.Items.Add(yellowItem); 
 
MessageListBoxItem greenItem = new MessageListBoxItem(Color.Green);
messageListBox1.Items.Add(greenItem);

Which gives us the following:

Empty MessageListBoxItems

Once we've created our items, we want to tweak them a bit through the use of the Title and Description properties which corresponds to the bold title text and body text respectively:

redItem.Title = "Big ole problem";
redItem.Description.Text = "Important information on the specifics of this error goes here.";
 
yellowItem.Title = "Minor issue";
yellowItem.Description.Text = "The world is going to end... just not today.";
 
greenItem.Title = "All is well";
greenItem.Description.Text = "Pay no attention to the man behind the curtain.";

Which brings us to this point:

MessageListBoxItems - With Text

And for good measure, lets add some eye candy with some existing icons:

redItem.Icon = CommonImages.StatusCritical24Icon;
yellowItem.Icon = CommonImages.StatusAtRisk24Icon;
greenItem.Icon = CommonImages.StatusHealthy24Icon;

to bring us to:

MessageListBoxItems - With Icons

ActionButton

Each MessageListBoxItem comes with a button ready for us... all we need to do is set it's text to make it visible:

redItem.ActionButton.Text = "Fix Error";

Of course to make it truly useful, we also have to manually wire up an event handler and the code to do something with the event:

redItem.ActionButton.Click += new EventHandler(ActionButton_Click);
 
...
 
void ActionButton_Click(object sender, EventArgs e)
{
   //Determine which button was clicked
   Button b = sender as Button;
   //Determine which MessageListBoxItem the button exists on
   MessageListBoxItem mlbi = b.Parent as MessageListBoxItem;
 
   //Do useful processing
 
   //Remove specified MessageListBoxItem
   messageListBox1.Items.Remove(mlbi);
}

MessageListBoxItems - With Button

CheckBox

Instead of using a button for a single action, we can use the built in CheckBox functionality to allow toggling of a setting.

Using the supplied CheckBox is similar to using the Button where we set the properties Text property and wire up and event handler... note that we are also required to set the CheckBox's Visible property to true:

yellowItem.CheckBox.Text = "Ignore this";
yellowItem.CheckBox.Visible = true;
yellowItem.CheckBox.CheckedChanged += new EventHandler(CheckBox_CheckedChanged);

Once wired up we can use the CheckBox very similar to how we used the ActionButton:

void CheckBox_CheckedChanged(object sender, EventArgs e)
{
   CheckBox cb = sender as CheckBox;
   MessageListBoxItem mlbi = cb.Parent as MessageListBoxItem;
 
   if (!mlbi.CheckBox.Checked)
   {
      //Do useful processing
      mlbi.GradientColor = (Color)mlbi.Tag;
   }
   else
   {
      //Do useful processing
      mlbi.GradientColor = Color.Gray;
   }
}

Which brings us to:

MessageListBoxItems - With CheckBox

Note the above example assumes that we are also storing the enabled color in the MessageListBoxItem's Tag property (as in the sample for this post).

Be aware that while you can use both the ActionButton and CheckBox... doing so isn't very advisable due to the way both controls are rendered together:

MessageListBoxItems - CheckBox and button

Link

In order to set the description of the MessageListItem we have to set Description.Text instead of just Text is because Description is a LinkLabel which gives is more control than just displaying text... it allows us to define a specific area to be a clickable hyperlink.

To set that up, we need to modify or replace the LinkArea property of the Description property to specify where the link should begin and for how long it will as well as wire up an event handler:

greenItem.Description.Text = "Pay no attention to the man behind the curtain.\nClick here for more information";
//Link starts on 48th character and is 31 character long
greenItem.Description.LinkArea = new LinkArea(48, 31);
greenItem.Description.LinkClicked += new LinkLabelLinkClickedEventHandler(Description_LinkClicked);
 
...
 
void Description_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
   //Do something based on link
}

To achieve:

MessageListBoxItems - With Link

Limitations

Like so many other of the Windows Home Server Controls, MessageListBox is lacking in a few ways.

Aside from it's limited designer support, it does also suffer from a bit of an issue... choppy redrawing which most often occurs whenever a MessageListBoxItem is added or removed from the visible list.

Ideally after a MessageListBox is populated, its contents should not be altered while visible. While this is not a requirement, doing so will reduce the likelihood of the various sub controls used in each MessageListBoxItem from flashing about.

Examples

Putting it all together, again I've provided a pair of add-ins that show off the simplicity of MessageListBox and how we can use it visually:

MessageListBoxItems - Example Add-ins

Downloads:

Conclusion

MessageListBox provides a simple way to create a rich list of color coded messages for a user provided the drawing issues are understood and worked around.

Next Time

I'm not sure yet... What would you like to see? I'd love to hear your ideas.

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels:

Sunday, December 30, 2007

I love my state!

To many... South Dakota is a backwater, podunk, cold as hell, boring, uninhabited wasteland with fowl-tasting water and a former powerful senator.

To me... it's not just home, but a place I thoroughly love.

Sunday night after attending the wedding of my good friend Sonja in the wee town of Colton, SD (pop ~650) I embarked at ~11:30 for the 30 min drive home to Madison (pop ~6500)... only to realize that I'd taken a wrong turn on my way out of town and attempted to turn around using the driveway to some private property... only to end up in the ditch:

In the ditch

Needless to say I was ticked, especially after I got myself more stuck, but also because it was my first time after living here for 8 years and driving only vehicles incapable of getting themselves out on their own.

Just 5 minutes after I got stuck and as I was thinking of walking the half mile back to town on that a driver on this low traffic road stops to ask if he can offer a hand... after some pushing I was still stuck.

A minute later another driver (with a pickup (a staple of South Dakota living (and with any luck, my next vehicle purchase (some day)))) stops and offers me a pull.

Only one problem... no one had a tow rope or chains with them... so both vehicles raced home to try to find something.

While they were gone I spent a few minutes trying to shovel some of the 4-6 inch deep snow (mixed with tall grass) away from the vehicle so that we'd be able to look underneath easier as well as have slightly more traction on the way up... not to mention taking a quick picture.

20 minutes later the pickup driver returns with a chain and after some quick rigging, he pulls me out and back on to the road and a Kurt Anderson became my hero for the time being.

This is part of why I love this state so... When we see someone along the side of the road in need of assistance... instinctively we stop to see if we can render assistance. We aren't worried that the person who is pulled over (or the person pulling over) might be some homicidal maniac or other crazy... we know all to well (or know someone who knows) what it's like to be stranded along the road in the middle of seemingly nowhere.

I know that I'll have to leave this fine state one day... but until then I get to enjoy every minute of it... even if that includes 50+ mph cross winds in the middle of a blizzard where people (like me) still feel comfortable driving down the interstate.

How many tabs is too many?

Ever wonder how many console tabs the Windows Home Server Console can display?

So did I... so I built a few extra projects and deployed them to my Home Server:

Projects Dir

The answer is... 100 and believe it or not... that's a bad thing!

100 Tabs

As much as I would like to see such wide spread WHS development that there were 100+ add-ins to choose from... it'll likely be a long while before we see anything like that ... it's also probably unlikely that when that day happens very many people (if any) will install that many add-ins... but for those that do an obvious problem will hit them hard... some tabs not being displayed.

Look again at the above image of all of the tabs being scrolled through. Missing a few important things isn't it?

When tabs are loaded, the assemblies they are contained within are loaded in alphabetical order and once the limit is reached, no new tabs are added to the Console and only warnings are added to the event HomeServerConsole log file:

[1]071230.131656.5468: Init: Error: Too many tabs - extra is ignored
[1]071230.131656.5625: Init: Error: Too many settings - extra is ignored
[1]071230.131656.6562: Init: Error: Too many tabs - extra is ignored
[1]071230.131656.7031: Init: Error: Too many settings - extra is ignored
[1]071230.131656.7656: Init: Error: Too many tabs - extra is ignored
[1]071230.131656.8906: Init: Error: Too many settings - extra is ignored
[1]071230.131657.4218: Init: Error: Too many tabs - extra is ignored
[1]071230.131657.6250: Init: Error: Too many settings - extra is ignored
[1]071230.131657.7031: Init: Error: Too many settings - extra is ignored

This is an interesting non-graceful failure as it is very possible that after a user adds too many tabs to their Home Server Console... they will not be able to easily remove an add-in or two to bring them back under the 100 tab limit using the Add-ins Settings page as they ordinarily would as it is very possible that it would be one of the first victims of this limit... after all it is located in the HomeServerConsoleTab.Storage.dll assembly which is pretty late in the alphabet

For reference, here is how the same non-graceful failure appears in the Settings dialog:

Settings - Start

Settings - End

Labels: ,

Tuesday, December 25, 2007

Aliens vs. Predator: Requiem - OMG WTF?

This afternoon I was compelled to join a friend and his cousin in seeing this... horrible movie, and aside from making me wish that I had that 86 minutes and $5.25 back... I left encouraged to not go back and watch the first Alien vs Predator movie (which I've never seen) or any of the original Alien movies (one or two of which I've seen), let alone read any of the comic books or give any more thought to the experience than what will be involved in writing this post.

This movie was bad, so very very bad. Not a Michael Jackson "you know I'm bad, I'm bad - you know it" bad, a Shredder "It feels so good to be so bad" bad, or even a "oh know my Windows Home Server burned down with the rest of my uninsured house and now I have nothing" bad ... but so horribly awful that... aside from wishing I was having dental work at the time, forgiveness for my friend and his suggestion of this film may never come and yet amazingly... it did have inklings of potential.

There is obvious some kind of back story to this movie other than "The Aliens and Predators try to kill each other", and had some of the following topics been covered... or at least included as captions at the bottom of the screen during the opening... some clarity would be gained:

  • What is the relationship between the Aliens and Predators?
  • Why is there a hybrid Alien/Predator?
  • Why does a single (implied) bad-ass Predator have to strip a fallen one for the equipment needed to take on the Aliens just after he arrives?
  • Why is the original Predator ship so stocked full of dangerous specimens?
  • What is the relationship between the crashed ship and the Predator who comes to clean up after it?
  • Why is that clean up a one man job?

Just to name a few.

I will give the Predator credit though... he does seem to be a firm believer in the Prime Directive as demonstrated by his careful removal of all physical evidence of the Aliens... but then I don't recall Captain Kirk or Picard killing and skinning someone who found them cleaning up.

I should mention that I am not a fan of horror or slasher movies... if I were I'm sure I would have enjoyed the fact that I fully expect that the following conversation likely occurred on set at one point:

It just occurred to me, we haven't gratuitously killed anyone in over 5 minutes.

Yea, we should fix that

I know lets have the stereotypical quasi sex scene which turns bad in the high school pool to try to keep the teenage boys interested

Good idea, hey though, we are starting to run out of money so lets lets turn down the lights a bit so as to hide some of the cheesiness

That's not a bad idea... in fact lets just stop using extra lights all together and break out some overused rain, not only will it add to the atmosphere, but will also let avoid those expensive and complicated long shots

My friend and his cousin dared to call this movie science fiction, a concept I balked at and said "if so... what was the lesson, moral or contemporary issue that it dealt with?"

The only explanation I could think of was that it had to do with trauma often caused to the average American family through the deployment of a parent overseas and the problematic reunifications that occur even when the parent returns unscathed.

The moral of the story was that that kids should be extra thrilled their fighting parent is home and tell them so immediately and without delay, never once letting them feel guilty for serving their country or being absent from their child's life for even a day... cause if they don't, their father is likely to be eaten by an alien and their entire town is will be nuked by their own government.

Lesson learned!

The one upshot of this movie... was that after seeing it I felt only slight less dumber than I had after watching the Sci Fi channel's horrendous mini-series "Tin Man"... (something I've yet to blog about) as I'd only wasted 83 minutes on AvP while I'd wasted ~4-6 hours on Tin Man (depending on commercials).

Indefinite WHS testing in VPC

In many homes this morning countless children screamed and yelled as they discovered Santa had visited and left them just what they'd asked for.

What follows is something I learned a few weeks ago and that made me act similarly... only I was giggling like a school girl.

This blog post last week was my Santa.

A major pain point I've encountered with testing custom code in an unactivated copy of Windows Home Server running in Virtual PC is that it automatically syncs the guest PC's clock to that of the host PC, ensuring only 30 days of testing before needing to reinstall, not so anymore with the host_time_sync section in a .vpc file:

<microsoft>
  <components>
    <host_time_sync>
      <enabled type="boolean">true</enabled>
    </host_time_sync>
  </components>

Needless to say I was quite let down when months ago I saw this blog post from the same author, saying there was no way to do it. What's worse is that I missed the comment saying how it is possible.

Now my test VPC will keep on reporting that it was installed on 12/2/2007, that today is 12/9/2007 and I've got 23 days until Windows requires activation... something it will keep thinking so long as I don't commit changes to the virtual hard disks.

If however I save changes to the undo disks the counter will proceed forward... until I throw out those changes and revert back to the previous state with a mouse click.

It should be noted that this kind of hack is largely worthless for piracy purposes (as far as Windows Home Server is concerned) and only useful for testing as it is only effective so long as you do not commit changed to the virtual hard disks... because if you do you allow the activation timer to keep on counting down and eventually expire.

Merry Christmas and Happy Testing!

Labels: ,

Monday, December 24, 2007

WHS Dev Tip #12: QButton, ConsoleToolBar, and LineBox

Q: What are some of the other Home Server Controls that I can take advantage of in my add-in?

A: Three of the most commonly used controls are QButton, ConsoleToolBar and LineBox which individually behave virtually identical to existing controls, only draw themselves in a more Home Server-ish style.

QButton

Likely the most commonly used Home Server Control is the simple QButton control which gives you a Vista like button... unfortunately does not offer as many options as the standard Button control, things like:

  • Height is locked
  • Limited TextImageRelation functionality
  • Changing the following properties does nothing:
    • ForeColor
    • BackColor
    • BackgroundImage
    • TextAlignment

Despite these and other differences, the QButton is still a fantastic way to easily get a little more Home Server-ish styling in ones add-in.

ConsoleToolBar

One of the staples of most add-ins is the common use of the blue ConsoleToolBar control as seen the majority of Microsoft and third-party add-ins alike that try to stay with a WHS like theme:

ConsoleToolBarButton - Existing Example

To add one to a Home Server Add-in control, it's simply a matter of dragging it to the form and then using the designer to add new ConsoleToolBarButtons:

Add ConsoleToolBarButton

Note: you are free to add any other object that inherits from ToolStripItem, ConsoleToolBarButton is the only control that maintains the theme.

One problem with using the designer to do this is that when a user moves the mouse over the button, the font color does not change as it does with the Microsoft built tabs:

Default ConsoleToolBarButton

vs

Existing ConsoleToolBarButton

This is due to the default constructor (required for and used by the Forms Designer) of ConsoleToolBar does not add a pair of event handlers to change the font color, instead we must do so ourselves if we want the effect:

consoleToolBarButton1.MouseLeave += new System.EventHandler(consoleToolBarButtons_MouseLeave);
consoleToolBarButton1.MouseEnter += new System.EventHandler(consoleToolBarButtons_MouseEnter);
consoleToolBarButton2.MouseLeave += new System.EventHandler(consoleToolBarButtons_MouseLeave);
consoleToolBarButton2.MouseEnter += new System.EventHandler(consoleToolBarButtons_MouseEnter);
 
...
 
private void consoleToolBarButtons_MouseEnter(object sender, EventArgs e)
{
   ConsoleToolBarButton button = sender as ConsoleToolBarButton; 
 
   button.ForeColor = Color.Black;
} 
 
private void consoleToolBarButtons_MouseLeave(object sender, EventArgs e)
{
   ConsoleToolBarButton button = sender as ConsoleToolBarButton;
   button.ForeColor = Color.White;
} 

Once added we'll get this:

Colorized ConsoleToolBarButton

One possible issue that may arise using the above method is the text color not reverting if the button is disabled after the MouseEnter event, something that will keep a MouseLeave event from ever being fired. Instead it is good to be aware of this edge case and manually change the color when disabling the button.

Line

All throughout the Microsoft settings pages we see a style not often seen since Visual Basic 6 applications we all the rage: colored horizontal lines.

Right off the bat we can use the Line control by dragging it to the form, however it can be rather finicky as it is used best when only one pixel tall, however other heights are certainly possible:

Lines

Problems can quickly be had if one attempts to change the size in the designer (ie without using the Properties window) where the line can get very large and unwieldy.

Furthermore, when the line is only a pixel tall it is almost impossible to click on to select and then move around on the form.

There is however a better way to use this throwback to a simpler time...

LineBox

The most common use for the Line control is through the LineBox control which looks and acts just like a GroupBox (ie a container control), only doesn't have a visible border and instead has a stylish blue line along the top next to the header text:

LineBox1

Unfortunately LineBox is another one of those controls written without the designer in mind, something we see when we find we are unable to change the header text in the designer.

Instead LineBox exposes a member field named Header which is nothing but a custom label which controls what is actually displayed. To modify it in code it is as easy as:

lineBox1.Header.Text = "Some Text Goes Here";

One upshot of exposing the full control instead of just a Text property is that we can tweak it and make it even prettier... or uglier:

LineBox2

Of course we can avoid manually setting the text this way if we create our LineBox programmatically:

LineBox lineBox2 = new LineBox("Header Text");

A problem that you will likely encounter with LineBox is that you do not know at design time the actual height of the header which can easily lead to a child control being overlapped by the header:

LineBox Overlap

Examples

Once again I have created a couple of simple add-ins which demonstrate how QButton, ConsoleToolBar, and LineBox can be used:

HomeServerConsole with Controls Example 2

Downloads:

Conclusion

QButton, ConsoleToolBar and LineBox are three semi-new controls that provide a fantastic way for a Home Server add-in developer to get the same functionality they are used to with existing controls, but with the benefit of staying with the Windows Home Server style of design.

Next Time

Next week we'll discuss the MessageListBox control, the very control that is used to display messages in the Home Network Health dialog and messages and the available and installed Add-ins.

Tomorrow though as a special Christmas gift, a little tip that made me giggle like a little girl when I learned it.

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels:

Tuesday, December 18, 2007

WHS Developer Tip #11: FancyListView

Q: How can make a ListView that looks more like what I see in the Home Server Console with so many images and progress bars?

A: Another one of the wonderful undocumented features of Windows Home Server is the FancyListView control (Microsoft.HomeServer.Controls, HomeServerControls.dll) that is used by all of the official Home Server Console tabs for displaying of the system's shares, users, computers and hard drives.

The first difference a user will notice is that it is drawn differently than a regular ListView, automatically making it look more Windows Home Server-ish in terms of it's shading, but also allows for the easy adding of images and progress bars in various different locations.

Terminology

Before digging in, lets go through a few terms used with ListViews so as to better understand the mechanics of what is used under the hood to draw a normal one.

A ListView is the actual control itself which has multiple different ways of displaying lists of data which are controlled by the View property which include:

  • LargeIcon - Each item appears as a full-sized icon with a label below it.
  • Details - Each item appears on a separate line with further information about each item arranged in columns. The left-most column contains a small icon and label, and subsequent columns contain sub items as specified by the application.
  • SmallIcon - Each item appears as a small icon with a label to its right.
  • List - Each item appears as a small icon with a label to its right. Items are arranged in columns with no column headers.
  • Tile - Each item appears as a full-sized icon with the item label and subitem information to the right of it. The subitem information that appears is specified by the application.

The most common View used in the Windows Home Server Console is Details which gives us the familiar row and column look.

A ListView contains a collection of ListViewItems named Items which corresponds to the item in the first column when in Details view.

Each ListViewItem has a collection of ListView.ListViewSubItems called SubItems which correspond to later items in the row.

In order to automatically display an image inside of a ListViewItem, a programmer would specify with ImageKey or ImageIndex property the value corresponding to an ImageList instance that has been set to the SmallImageList property, in C# this would look like (assuming a ListView named listView1 has been created on the form and it's View property has been set to Details):

//Create ImageList
ImageList imageList1 = new ImageList();
//Adjusting the size of the images can change the height of a row of data
imageList1.ImageSize = new Size(32, 32);
imageList1.ColorDepth = ColorDepth.Depth32Bit;
 
//Add some image to the list with no keys
imageList1.Images.Add(CommonImages.ErrorImage32x32);
imageList1.Images.Add(CommonImages.HomeServerImage32x32);
imageList1.Images.Add(CommonImages.InformationImage32x32);
 
//Add an image to the list with the key Healthy key
imageList1.Images.Add("Healthy", CommonImages.StatusHealthy32);
//Add an image to the list with the key Warning key
imageList1.Images.Add("Warning", CommonImages.WarningImage32x32);
 
//Associate the ImageList with the ListView
listView1.SmallImageList = imageList1;
 
 
//Create first ListViewItem
ListViewItem listViewItem1 = new ListViewItem();
listViewItem1.Text = "Item 1";
//Display the first image in the list
listViewItem1.ImageIndex = 0;
listView1.Items.Add(listViewItem1);
 
 
//Create second ListViewItem
ListViewItem listViewItem2 = new ListViewItem();
listViewItem2.Text = "Item 2";
//Display the image from the ImageList with the Warning key
listViewItem2.ImageKey = "Warning";
listView1.Items.Add(listViewItem2);
 
 
//Add Column to the ListView to enable item(s) to show up
ColumnHeader column1 = new ColumnHeader();
column1.Text = "Column 1";
column1.Width = 100;
listView1.Columns.Add(column1);

Which gives us:

Standard ListView

This is how a normal ListView functions and a FancyListView works in virtually the same way, only it adds to new ListViewSubItems to the mix.

ImageSubItem

A drawback of the stock ListViewSubItem class is that it does not have any built-in support for images and leaves such work to the programmer to implement themselves. This is where ImageSubItem comes into play, providing the ImageIndex and ImageKey properties that use the same ImageList as any other ListViewItems on the list.

To expand the earlier example, lets start with the following nearly identical code (assuming a FancyListView named fancyListView1 has been created on the form and it's View property has been set to Details):

//Create ImageList
ImageList imageList1 = new ImageList();
//Adjusting the size of the images can change the height of a row of data
imageList1.ImageSize = new Size(32, 32);
imageList1.ColorDepth = ColorDepth.Depth32Bit;
 
//Add some image to the list with no keys
imageList1.Images.Add(CommonImages.ErrorImage32x32);
imageList1.Images.Add(CommonImages.HomeServerImage32x32);
imageList1.Images.Add(CommonImages.InformationImage32x32);
 
//Add an image to the list with the key Healthy key
imageList1.Images.Add("Healthy", CommonImages.StatusHealthy32);
//Add an image to the list with the key Warning key
imageList1.Images.Add("Warning", CommonImages.WarningImage32x32);
 
//Associate the ImageList with the FancyListView
fancyListView1.SmallImageList = imageList1;
 
 
//Create first ListViewItem
ListViewItem listViewItem1 = new ListViewItem();
listViewItem1.Text = "Item 1";
//Display the first image in the list
listViewItem1.ImageIndex = 0;
fancyListView1.Items.Add(listViewItem1);
 
 
//Create second ListViewItem
ListViewItem listViewItem2 = new ListViewItem();
listViewItem2.Text = "Item 2";
//Display the image from the ImageList with the Warning key
listViewItem2.ImageKey = "Warning";
fancyListView1.Items.Add(listViewItem2);
 
 
//Add Column to the FancyListView to enable item(s) to show up
ColumnHeader column1 = new ColumnHeader();
column1.Text = "Column 1";
column1.Width = 100;
fancyListView1.Columns.Add(column1);

Which in turn displays the following for us:

FancyListView - Just ListViewItems

In order to add a pair of ImageSubItems that use an image from the existing Image List, we need only add the following code:

//Create ImageSubItem using ImageIndex and add to first ListViewItem
FancyListView.ImageSubItem imageSubItem1 = new FancyListView.ImageSubItem();
imageSubItem1.Text = "Sub Item 1";
//Set to imageIndex 1
imageSubItem1.ImageIndex = 1;
listViewItem1.SubItems.Add(imageSubItem1);
 
//Create ImageSubItem using ImageKey and add to second ListViewItem
FancyListView.ImageSubItem imageSubItem2 = new FancyListView.ImageSubItem();
imageSubItem2.Text = "Sub Item 1";
//Set image with Healthy key
imageSubItem2.ImageKey = "Healthy";
listViewItem2.SubItems.Add(imageSubItem2);
 
//Add an extra Column to ListViewFancy to enable new Sub Items to show up
ColumnHeader column2 = new ColumnHeader();
column2.Text = "Column 2";
column2.Width = 100;
fancyListView1.Columns.Add(column2);

Which makes our example look something like this:

FancyListView - ImageSubItems

FilledBarSubItem

Another neat feature we've seen on the Computers & Backups tab is a progress bar, something that programmatically behaves not unlike the progress bars and SubItems we've already used or added.

To create and add them, we need only add this code to the end of our running example:

//Create new Filled Bar of the Rectangle style
FancyListView.FilledBarSubItem filledBar1 = new FancyListView.FilledBarSubItem();
filledBar1.Text = "Bar 1";
filledBar1.PercentageFilled = 33;
filledBar1.DrawStyle = FancyListView.FilledBarStyle.Rectangle;
listViewItem1.SubItems.Add(filledBar1);
 
//Create new Filled Bar of the RoundedRectangle style
FancyListView.FilledBarSubItem filledBar2 = new FancyListView.FilledBarSubItem();
filledBar2.Text = "Bar 2";
filledBar2.PercentageFilled = 66;
filledBar2.DrawStyle = FancyListView.FilledBarStyle.RoundedRectangle;
listViewItem2.SubItems.Add(filledBar2);
 
 
//Add third column to allow new FilledBars to show up
ColumnHeader column3 = new ColumnHeader();
column3.Text = "Column 3";
column2.Width = 150;
fancyListView1.Columns.Add(column3);

which makes our example now look like:

FancyListView - FilledBarSubItem

Aside from our ability to change the style of the bar (Rectangle vs RoundedRectangle) which we see demonstrated by the two FilledBarSubItem instances used above, another very useful option we have is the ability to specify additional colors for ranges.

Ordinarily if you need to specify some visual range difference, the ProgressBar control isn't enough, instead other controls may be employed or worse yet... writing your own which would likely involve manually checking the ranges ourselves, instead FilledBarSubItem gives us the following properties to do that for us:

  • WarningColor
  • WarningPercentage
  • CriticalColor
  • CriticalPercentage

Together we can get automatic colorization:

FancyListView - Colorized FilledBarSubItem

All by just by these lines to the above running example:

filledBar1.WarningPercentage = 33;
filledBar1.WarningColor = Color.Orange;
filledBar1.CriticalPercentage = 66;
filledBar1.CriticalColor = Color.Red;
 
filledBar2.WarningPercentage = 33;
filledBar2.WarningColor = Color.Orange;
filledBar2.CriticalPercentage = 66;
filledBar2.CriticalColor = Color.Red;

And that's in addition to being able to specify an arbitrary color for our bar in the first place.

Refreshing

Unlike a control like the TextBox or Button classes, simply updating properties of a ImageSubItem or FilledBarSubItem will not cause them to visually be updated because they aren't controls, instead they are only visually updated when the parent FancyListView is redrawn, something that ordinarily will occur when ever the containing form is hidden and then shown, something is dragged over the control, or you click on it.

Instead of relying on the system or the user, you as the programmer can call the FancyListView's Invalidate() or Refresh() methods to force it to redraw itself and all of the ImageSubItem or FilledBarSubItem instances so that any chances are then visible just as you can with most other controls, however FancyListView which inherits from ListView offers an even better option, namelyRedrawItems() which allows you to redraw only those items you want to in the list which can be as simple as:

filledBar1.PercentageFilled += 1;
filledBar2.PercentageFilled += 1;
 
fancyListView1.RedrawItems(startIndex, endIndex, false);

Sizing and Stretching

In the previous examples I've focused on using icons with a size of 32x32 which causes each row in the FancyListView to be 32 pixels tall. Want to make it shorter? Simply change the size of the ImageList that the FancyListView uses.

One quirk of using this method to define the size of our rows, is that it is not uncommon to have a large 32x32 image for the first column, but then want a small 16x16 image for a status icon... not unlike how the Home Server Console notes drive or duplication status, you'll find that the smaller image will automatically be stretched to fill the available area.

In order to make such a small image stay small, you should use a larger image that contains the smaller image, not unlike how the CommonImages class exposes GrayIcon, GreenIcon and RedIcon which are each only 16x16, but also available as part of larger 32x32 images as GrayIcon32, GreenIcon32 and RedIcon32 as well.

ListViewItemSorter

Another one of the advantages of FancyListView is that does sorting right out of the box without any work from you as a programmer whenever a user clicks on a column header.

With an ordinary ListView, simply creating a class that implements the IComparer interface and setting an instance of it to the ListViews ListViewItemSorter property is all that is needed. FancyListView takes this a step further by defining a custom sorting class ListViewColumnSorter (Microsoft.HomeServer.Controls, HomeServerControlls.dll) which it automatically uses and requires.

Unfortunately an ordinary custom sorting class that simply implements the IComparer interface cannot be used because internally FancyListView.ListViewItemSorter typecasts the value to a ListViewColumnSorter, which forces any other sorter to from ListViewColumnSorter.

Examples

I have built a pair of sample add-ins that demonstrate a few of the things discussed above in a (very) mock (and not very accurate) Shared Folders like display which shows off several static ImageSubItems and a FilledBarSubItem that is updated and then moved once it's maximum value has been reached:

FancyListViewDemo

Downloads:

Conclusion

FancyListView provides an easy to use mechanism for displaying additional information to a user by allowing images in any columns and progress bars to better inform the user of the current state of the system or whatever else the add-in wants to say.

Next Time

Next week we'll dive into a few more controls in the HomeServerControls.dll assembly, some of their quirks and how they can be better used to make our add-ins look more at home in the Home Server Console.

Note: The information in this post is based on undocumented and at times deduced information on Windows Home Server and is not officially supported or endorsed by Microsoft and could very easily be wrong or subject to change in future, so please take it and everything else said on this blog with a grain of salt and use with caution.

Labels: