Filter Weekdays from a Date Range
Integrating Twitter Feeds in Web Applications

WPF ListBox as Bar Chart

A ListBox displays a list of items, and one (or more) item(s) can be selected. With WPF it’s possible to define a complete different look for ListBox elements. With templates items can be customized with a complete different look, and the ListBox itself can be customized with a control template. This way a ListBox can look like a bar chart. This article demonstrates changing the look of a ListBox to a bar chart.

Data Source

First data are needed. I’ve created a simple class that returns a list of numbers with the type IEnumerable<int>:

public class DataFactory { public IEnumerable<int> GetData() { return new int[] { 3, 5, 8, 6, 11, 7 }; } }

 

The class is instantiated by the ObjectDataProvider which invokes the method GetData to return the list of numbers.

<ObjectDataProvider x:Key="someData" ObjectType="{x:Type local:DataFactory}" MethodName="GetData" />

Binding the ListBox

A ListBox is bound to the data by setting the ItemsSource property, and defining the DataContext of a parent element from the ListBox.

<Grid DataContext="{Binding Source={StaticResource someData}}"> <ListBox ItemsSource="{Binding}" /> </Grid>

Running the application a default representation of the ListBox and its items is shown.

image

Item Template

To display the values as bars, a DataTemplate can be created. The template contains a red rectangle where the Width property is bound to the value returned from the collection item.

<DataTemplate x:Key="BarChartItemTemplate"> <Border Width="200" Height="50"> <Grid> <Rectangle Fill="Red" StrokeThickness="0" Height="40" Width="{Binding}" Margin="3" HorizontalAlignment="Right" VerticalAlignment="Bottom" /> </Grid> </Border> </DataTemplate>

With the ListBox, the ItemTemplate references the data template defined earlier.

<ListBox ItemsSource="{Binding}" ItemTemplate="{DynamicResource BarChartItemTemplate}" />

Running the application with its current state the rectangles are already visible as shown in the following figure. However, as the values returned from the collection are small, the rectangle has a small width.

image

To change the width of the rectangle based on the existing values returned from the collection it would be possible to use a converter. A converter class implements the interface IValueConverter and is configured with the binding. Another option – this one is used here – is to create a transformation. The rectangle is scaled by using a ScaleTransform setting ScaleX to 20 to scale the rectangle in x direction by 20.

<Rectangle Fill="Red" StrokeThickness="0" Height="40" Width="{Binding}" Margin="3" HorizontalAlignment="Right" VerticalAlignment="Bottom"> <Rectangle.LayoutTransform> <ScaleTransform ScaleX="20" /> </Rectangle.LayoutTransform> </Rectangle>

With this transformation the rectangles look better. With the configuration as it is now, the first values are on top of the ListBox, and the last items on bottom. A behavior that is usually expected with ListBox controls. However, using a bar chart display usually it looks better to arrange the values in a horizontal way, starting with the first value on the left. This is done next.

image

Rotating the Panel

To display the values horizontally within a bar chart the complete panel from the ListBox can be rotated. An ItemsPanelTemplate defines the panel for the items, and this is rotated by 90 degrees and scaled by –1 in the x direction to have the first items on the left side.

<ItemsPanelTemplate x:Key="BarChartItemsPanel"> <VirtualizingStackPanel IsItemsHost="True"> <VirtualizingStackPanel.LayoutTransform> <TransformGroup> <RotateTransform Angle="90" /> <ScaleTransform ScaleX="-1" ScaleY="1" /> </TransformGroup> </VirtualizingStackPanel.LayoutTransform> </VirtualizingStackPanel> </ItemsPanelTemplate>

With the ListBox control the ItemsPanelTemplate is assigned to the ItemsPanel property.

<ListBox ItemsSource="{Binding}" ItemTemplate="{DynamicResource BarChartItemTemplate}" ItemsPanel="{DynamicResource BarChartItemsPanel}" />

Running the application now, the items are displayed horizontally and the first items in the list are shown left.

image

Adding Values to the Display

If text values should be displayed in the ListBox as well beside the red rectangles, the ItemTemplate can be changed. Here, a TextBlock is added to the DataTemplate that binds the Text property to the same value as the Width property of the rectangle. As the TextBlock is in the same position of the grid as the rectangle it is just shown on top of it.

<DataTemplate x:Key="BarChartItemTemplate"> <Border Width="200" Height="50"> <Grid> <Rectangle Fill="Red" StrokeThickness="0" Height="40" Width="{Binding}" Margin="3" HorizontalAlignment="Right" VerticalAlignment="Bottom"> <Rectangle.LayoutTransform> <ScaleTransform ScaleX="20" /> </Rectangle.LayoutTransform> </Rectangle> <TextBlock Margin="20" FontWeight="Bold" HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding}"> <TextBlock.LayoutTransform> <ScaleTransform ScaleX="-1" ScaleY="1" /> </TextBlock.LayoutTransform> </TextBlock> </Grid> </Border> </DataTemplate>

Now both the rectangles and the values are shown when running the application.

image

Does this look like a ListBox? It has the same functionality as a list box, just  different look. Using XAML it’s easy to change the look in any way.

More information on WPF and XAML in my workshops and in the book Professional C# 4 and .NET 4.

Christian

CN innovation

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Indhy

Seriously helped me a lot for my similar problem.. Thanks for this wonderful article

The comments to this entry are closed.