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