One of the main strengths of WPF is the ability to visualize ordinary data in a different way. In this post, I’ll go over how we can represent the 5 star rating of our images defined in this post as a simple WPF bar graph. Also demonstrated is the use of the Tooltip item in WPF that will be used to display detailed information of the image when the user hovers over a bar in our graph. The final result will look similar to this:
This bar chart is generated using our ListBox control, and a series of canvases, each one representing an image in our collection. In order to override the default vertical orientation of a ListBox you must assign a different content control to the ItemsPanel property. In this case, we override the default vertical orientation Stack Panel of the ListBox with another StackPanel with an orientation of horizontal. This will render the ListBox items from left to right.
1: <ListBox.ItemsPanel>
2: <ItemsPanelTemplate>
3: <StackPanel Orientation="Horizontal" />
4: </ItemsPanelTemplate>
5: </ListBox.ItemsPanel>
The next item to tackle is the bar chart. This rendering is made possible through the use of a Data Template. A canvas with a red background color is represented for each item being bound to the list. A scaling transformation (on the Y-axis) is issued on each canvas using a value converter that multiplies the star rating by 20 to obtain a height. Keep in mind this height is a ratio, and not a pixel height.
Value Converter:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Windows.Data;
6:
7: namespace ItemsPanel
8: {
9: public class RatingHeightConverter : IValueConverter
10: {
11: #region IValueConverter Members
12:
13: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
14: {
15: if (value == null)
16: return 0;
17: int obj = (int)value;
18: return obj * 20;
19:
20: }
21:
22: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
23: {
24: throw new NotImplementedException();
25: }
26:
27: #endregion
28: }
29: }
Data Template Definition:
1: <ListBox x:Name="lbResults" ItemsSource="{StaticResource FavoriteImages}">
2: <ListBox.ItemsPanel>
3: <ItemsPanelTemplate>
4: <StackPanel Orientation="Horizontal" />
5: </ItemsPanelTemplate>
6: </ListBox.ItemsPanel>
7: <ListBox.ItemTemplate>
8: <DataTemplate>
9: <Canvas Width="20" Height="1" Background="Red" Margin="10,0,0,0">
10: <Canvas.RenderTransform>
11: <ScaleTransform CenterX="1" CenterY="1"
12: ScaleY="{Binding Path=ImageRating, Converter={StaticResource RatingHeightConverter}}" />
13: </Canvas.RenderTransform>
14: </Canvas>
15: </DataTemplate>
16: </ListBox.ItemTemplate>
17: </ListBox>
This will render the following bar chart:
While this does allow the user to visualize the image data in a different fashion. It lacks usability in the sense that the user does not know which specific items are represented for each bar displayed. A way to provide this functionality is by adding a tooltip to the canvas defined in the Data Template. Every visual control in WPF has a tooltip property. A tooltip is a content control and therefore can contain any number of visual elements. In this case, a Stack Panel is defined that will display the detailed information of the image including the image itself, image name and it’s 5 star rating (rating user control is defined in this post, and is assigned to the ToolTip property of the canvas.
1: <Canvas.ToolTip>
2: <ToolTip>
3: <StackPanel Height="300">
4: <Image Margin="10" Width="250" Height="200" Stretch="Fill" Source="{Binding Path=ImageHref}" />
5: <Label Content="{Binding Path=ImageName}" />
6: <Label Content="{Binding Path=ImageRating,Converter={StaticResource RatingConverter}}" />
7: </StackPanel>
8: </ToolTip>
9: </Canvas.ToolTip>
The final definition of our list box is as follows:
1: <ListBox x:Name="lbResults" ItemsSource="{StaticResource FavoriteImages}">
2: <ListBox.ItemsPanel>
3: <ItemsPanelTemplate>
4: <StackPanel Orientation="Horizontal" />
5: </ItemsPanelTemplate>
6: </ListBox.ItemsPanel>
7: <ListBox.ItemTemplate>
8: <DataTemplate>
9: <Canvas Width="20" Height="1" Background="Red" Margin="10,0,0,0">
10: <Canvas.RenderTransform>
11: <ScaleTransform CenterX="1" CenterY="1"
12: ScaleY="{Binding Path=ImageRating, Converter={StaticResource RatingHeightConverter}}" />
13: </Canvas.RenderTransform>
14: <Canvas.ToolTip>
15: <ToolTip>
16: <StackPanel Height="300">
17: <Image Margin="10" Width="250" Height="200" Stretch="Fill" Source="{Binding Path=ImageHref}" />
18: <Label Content="{Binding Path=ImageName}" />
19: <Label Content="{Binding Path=ImageRating,Converter={StaticResource RatingConverter}}" />
20: </StackPanel>
21: </ToolTip>
22: </Canvas.ToolTip>
23: </Canvas>
24: </DataTemplate>
25: </ListBox.ItemTemplate>
26: </ListBox>
Full Source Code for this example is available here.