Recently I’ve been asked how a list of graphical elements can be positioned, and the elements should be selectable. What panel could be used for this – a list of elements, and an element should be selectable – usually that’s the job of a ListBox. However, how can the elements in the ListBox be positioned using X/Y coordinates? For this job a Canvas can be used. Using a Canvas element for the ListBox turned out to be really simple as this article describes.
First I’m creating an Item type that should be displayed and contains coordinate information:
public class Item { public double X { get; set; } public double Y { get; set; } public string Name { get; set; } public string Color { get; set; } }
The collection of sample items is created within the ItemsFactory class:
public class ItemsFactory { private List<Item> items; public IEnumerable<Item> Items { get { return items ?? (items = new List<Item>() { new Item { Name = "One", X = 33, Y = 25, Color="Red" }, new Item { Name = "Two", X = 88, Y = 11, Color="Green" }, new Item { Name = "Three", X = 44, Y = 99, Color="Blue" } }); } } }
To display the elements within the view, the ItemsFactory is defined within resources and this resource is accessed applying a DataContext. The ListBox is bound to the Items property of the ItemsFactory and thus displays the items. The default view of the ListBox is just a list of strings, in this case the Item class didn’t override the ToString method and thus only the name of the classes is displayed.
<Window x:Class="ObjectListSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ObjectListSample" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <local:ItemsFactory x:Key="sampleItems" /> </Window.Resources> <Grid DataContext="{StaticResource sampleItems}"> <ListBox ItemsSource="{Binding Items}" /> </Grid> </Window>
The display can be changed by defining an ItemTemplate for the items of the ListBox. The items are displayed as an ellipse within a Canvas element. As it’s contained within a Canvas the Ellipse can be positioned with Canvas.Left and Canvas.Top. The position information is taken from the X and Y properties of the Item. Beside the position also the Color and Name properties of the Item are used for the display.
<Style x:Key="objectList" TargetType="ListBox"> <Setter Property="ItemTemplate"> <Setter.Value> <DataTemplate> <Canvas> <Grid Canvas.Left="{Binding X}" Canvas.Top="{Binding Y}"> <Ellipse Fill="{Binding Color}" Width="50" Height="40" /> <ContentPresenter Content="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </Canvas> </DataTemplate> </Setter.Value> </Setter> </Style>
Applying the style for the ListBox the new display is ready.
<ListBox Style="{StaticResource objectList}" ItemsSource="{Binding Items}" />
As the screenshot shows, the items are shown according the values of the Item objects within a Canvas. Does this look lie a ListBox? It’s a ListBox! The items can also be selected. The screenshot shows element Two as selected element.
Christian
More information in my WPF workshops
Comments
You can follow this conversation by subscribing to the comment feed for this post.