WPF and Silverlight Super-Productivity: ListBoxes
Except that statement is not true anymore. Not in WPF and Silverlight anyway, where ListBoxes have evolved from simplistic controls to true workhorse objects. ListBoxes have been around since the beginning of Windows (and other GUIs) and have served a pervasive yet simple purpose, which can be summed up as “show me a list of labels in a list with a scroll bar.” A premise that has its uses but is not sophisticated enough for advanced data presentation, which is why developers often use special controls such as “data grids” or “list views” among others. In WPF and Silverlight, however, ListBoxes are so flexible and powerful that they are the first choice for just about anything. In fact, WPF originally shipped without a data grid control since ListBoxes all but eliminated that need. Developer perception, however, was different and the power of the ListBoxes went largely unnoticed. That is reason enough for me to write an article that displays the ease, flexibility, and power of ListBoxes.
A Simple Scenario
In the scenario I chose as a basis for my examples, I have a simple window, which is mainly occupied by a ListBox, plus a drop-down list in the top-right corner that allows the user to switch between different views of the same ListBox. The event handler in the code-behind file handles changing ListBox styles. This code uses the selected index of the drop-down list and then loads and assigns styles from resource dictionaries accordingly (download the example file associated with this article for more details).
The actual ListBox is rather simple. This code defines it:<ListBox x:Name="RestaurantList"
Grid.Row="1" Margin="8" />
As far as ListBox development in this article goes, that is about it. We have a ListBox positioned inside the main window’s grid area (in the second row) with a margin of 8 pixels all around. The ListBox has a name, so we can assign it some data from the code-behind file (which alternatively, I could have also accomplished with a binding expression) and I set the “DisplayMemberPath” right here, which defines which field/property from the data source should be displayed within the list.
The data itself could come from a variety of places. In a real-world implementation, the data would probably come from a database or a service. To keep this example self-contained (so you can download and run it without having to create and configure a database), I created a fake data source which I populate in code. My example data is a list of restaurants with associated names and addresses. I also create random ratings (1-5 stars) every time the list is created, plus a few other pieces of data that I’ll use throughout this example. This data is simply loaded in the constructor of the MainWindow class and assigned as the item’s source of the ListBox:public MainWindow()
There you have it! This is as complex as the programming part of the ListBox gets. Everything you see in this article (feel free to glance at the screen shots ahead) uses this simple setup, which I will not touch or modify from here on forward. Everything demonstrated in this article is accomplished by means of styles. This in itself is a crucial piece of the puzzle, because it demonstrates how easy it is to change and enhance applications created in this fashion, even if these applications were never originally designed for that purpose. This ability is what ultimately makes this approach so flexible and maintainable. It also is what makes this approach so productive, since developers can initially create simple setups that are later enhanced with more advanced views.
Figure 1 shows what this setup looks like. As you can see, the ListBox is little more than a list of data-bound items with the names of the restaurants (which was defined as the display member path in the XAML above) shown as the label. Since the list is too long to fit, a vertical scroll bar appears, allowing the user to scroll up and down. This is the familiar appearance of ListBoxes as it has been used unchanged in decades of graphical user interfaces. It serves its purpose well, but it is very limited in usefulness for advanced data applications and data visualizations.
Figure 1: A simple data-bound ListBox.
NOTE: In my example, I chose WPF as the implementation technology, but everything shown here also applies to Silverlight.
Why WPF/Silverlight ListBoxes Are Better
In WPF and Silverlight, ListBoxes are much more useful. The simple view shown in Figure 1 is just a default. As far as WPF and Silverlight are concerned, ListBoxes have a few distinct characteristics: For one, ListBoxes are bound to a data source, resulting in a list of items. (Data sources can be anything that is enumerable, so DataSets, Collections, List<T>,… are all valid data sources for ListBoxes). Each item in the list is positioned at a certain place within the control. Creating a top-to-bottom stack of labels is the layout shown in Figure 1. However, this is just a default and - as you’ll see in this article - you can change this default and even extend the ListBox at will. Finally, each item within that list is designable. While showing a single label as a caption is a default, it turns out that each item represents its own little microcosm of a user interface that can contain any composition of WPF/Silverlight controls.
The combination of all these aspects makes for an incredibly flexible and powerful setup. I would go as far as saying than any time you have to display anything that binds to IEnumerable<T> (any “list of things”, basically) you should first and foremost think of using a ListBox and only switch to other control options if you have a specific need, and that switch is based on an educated opinion about the specific requirements. You do not want to switch to a different control as your default option. Not to a data grid, because a ListBox can easily be styled as a data grid (see below) and, in fact, a ListBox offers more flexibility than many data grid controls. Not to a ListView, because it is trivial to turn a ListBox into a ListView. Not a carousel control with a 3D view, because you can easily write a style that accomplishes this. And so on, and so on. In fact, one of the great advantages of using ListBoxes is that you can so easily turn a ListBox into just about anything else.
I have often said that I wish 3rd-party vendors would stop creating WPF and Silverlight controls and instead they should start creating styles. I would much rather buy a ListBox style that turns my data into a data grid than buy a data grid control. I would rather buy a carousel style than a carousel control. And so on. It provides a lot more freedom. Also note that the techniques shown in this article are very reusable. You may decide that some of the styles shown in this article take some effort to create. However, a key aspect to understand is that you only have to create these styles once and you can then apply the styles to all your lists. This makes development of many data visualizations much simpler, because you can create a simple ListBox and then worry about the exact visual appearance later. It also makes it extremely easy to retrofit your applications with different or newer data visualizations. This approach provides excellent maintainability and flexibility. Compare this to switching your application from using one 3rd-party’s data grid to another’s!
By: Markus Egger
Markus is the founder and publisher of CODE Magazine and EPS' President and Chief Software Architect. He is also a Microsoft RD (Regional Director) and the one of the longest (if not THE longest) running Microsoft MVPs (Most Valuable Professionals). Markus is also a renowned speaker and author.
Markus' spends most of his time writing production code. The projects Markus has worked on include efforts for some of the world's largest companies including many Fortune 500 companies. Markus has also worked as a contractor for Microsoft (including the Visual Studio team). Markus has presented at many industry events, ranging from local user groups to major events such as MS TechEd. Markus' written work has been published extensively and in magazine ranging from MSDN Magazine, to Visual Studio Magazine, and of course in Markus' own CODE Magazine and much more. Markus is a supporter of communities in North America, Europe, and sometimes even beyond.
Markus currently focuses on development in .NET (Windows, Web, Windows Phone, and WinRT) as well as Android and iOS. He is passionate about overall application architecture, SOA, user interfaces and general development productivity and building maintainable and reusable systems.
In his spare time, Markus is an avid windsurfer, scuba diver, ice hockey player and world traveler. On a rainy day, he is known to enjoy a good game on his PC or Xbox.