How to make WPF listview display Images and Labels dynamically - wpf

I'm having quite a difficult time trying to create the UI for a WPF Window. I'm trying to display (dynamically) a bunch of Movie Posters with the name of the movie directly under the image. ItemsSource is assigned to a list of Images via foreach iteration. The Image files themselves may be different sizes, but as shown below I will be setting a uniform size.
Basically, my goal is for it to look something like this:
So far, My code only displays a window with one large horizontal row(?) with the image in the center and no label. Here's my XAML code:
<Window x:Name="TVWindow" x:Class="PACS_Pre_Alpha.TV"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TV" Height="746" Width="1000" ResizeMode="NoResize">
<Grid x:Name="TVGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<ListView x:Name="TvBox" HorizontalAlignment="Left" Height="648" VerticalAlignment="Top" Width="994" Grid.Row="5" Grid.Column="5">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
<Image Source="{Binding ImageData}" HorizontalAlignment="Center" VerticalAlignment="Top" />
<TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
My movies are added with this C# code:
foreach (string tvf in ContentFiles)
{
string ContentTitle = System.IO.Path.GetFileNameWithoutExtension(tvf);
MovieData cnt = new MovieData();
cnt.ImageData = LoadImage(ActualImage);
cnt.Title = ContentTitle;
ContentDataList.Add(cnt);
}
TvBox.ItemsSource = ContentDataList;
Edit: I have changed my XAML Markup as #MarkFeldman suggested, but now nothing appears.
Edit: It currently looks like this:

You're going to provide more info about the data itself i.e. what's it's format, how are you assigning it to the ItemsSource etc. For one thing you're not setting the ItemTemplate, so you might want to look at that first. For example if you have a class containing your movie data that looks like this:
public class MovieData
{
private string _Title;
public string Title
{
get { return this._Title; }
set { this._Title = value; }
}
private BitmapImage _ImageData;
public BitmapImage ImageData
{
get { return this._ImageData; }
set { this._ImageData = value; }
}
}
Then you would display it with something like this:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
<Image Source="{Binding ImageData}" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
UPDATE:
Sorry, I thought it was obvious that you still needed to use a UniformGrid. Here is what your full XAML should look like:
<ListView x:Name="TvBox" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" HorizontalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Image Source="{Binding ImageData}" HorizontalAlignment="Stretch" VerticalAlignment="Top" Stretch="UniformToFill" />
<TextBlock Text="{Binding Title}" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I've already provided you with the MovieData class, so here's what your Window code should look like:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.TvBox.ItemsSource = new MovieData[]
{
new MovieData{Title="Movie 1", ImageData=LoadImage("image.jpg")},
new MovieData{Title="Movie 2", ImageData=LoadImage("image.jpg")},
new MovieData{Title="Movie 3", ImageData=LoadImage("image.jpg")},
new MovieData{Title="Movie 4", ImageData=LoadImage("image.jpg")},
new MovieData{Title="Movie 5", ImageData=LoadImage("image.jpg")},
new MovieData{Title="Movie 6", ImageData=LoadImage("image.jpg")}
};
}
// for this code image needs to be a project resource
private BitmapImage LoadImage(string filename)
{
return new BitmapImage(new Uri("pack://application:,,,/" + filename));
}
}
In this example I'm assuming there is an image in your project called "image.jpg" which has been set to build action "Resource", if your images come from elsewhere then you'll need to modify the LoadImage code accordingly.

I have done something very similar with UniformGrid I see you did not set the Rows of your UniformGrid. I did this In my Game App. Good approach but difficult to get right. Set an ItemTemplate. And try an ItemsControl Outer Object instead of listview
<ItemsControl IsEnabled="{Binding GameBoardEnabled}"
x:Name="_board"
ItemsSource ="{Binding Board}"
ItemTemplate= "{DynamicResource GamePieceTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!--<StackPanel/>-->
<UniformGrid
Columns="{Binding Columns}"
Rows ="{Binding Rows}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

Related

Get current binding index

My XAML code will creates Labels in WPF window. How can I make each Label's Content contain its position rendered from ItemSource ?
Currently, the result is: AAA BBB CC ( They are 3 labels )
What I want is: 1 2 3 ( They are 3 label or maybe 0 1 2, because the index base on 0 )
<ItemsControl Name="m_Header">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Margin="-2,0,0,0"
Width="{Binding Path=Columns[0].ActualWidth, ElementName=m_DataGrid}"
Content="{Binding}" FontSize="15" Foreground="#777" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
There is no Index property defined in the ItemsControl class, so there is no way to show that value. However, there is a trick that you can use to get what you want. If your ItemsControl.AlternationCount property is set to a suitably high number, then you can use the ItemsControl.AlternationIndex property to do the same thing for you:
<ItemsControl AlternationCount="999"><!--Set this as high as you need-->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Margin="-2,0,0,0" Width="{Binding Path=Columns[0].ActualWidth,
ElementName=m_DataGrid}" Content="{(ItemsControl.AlternationIndex), RelativeSource={
RelativeSource TemplatedParent}}" FontSize="15" Foreground="#777" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want the numbers to start at a different number, you can add a Converter to simply add or subtract the relevant value from each number.
Adding to #sheridan answer.
Depending on your underlying datasource you might be able use the source count property to set the AlternationCount
Model
public class DemoViewModel {
public ObservableCollection<string> Products { get; set; }
}
Setup DataContext
public MainWindow() {
InitializeComponent();
var vm = new DemoViewModel();
vm.Products = new ObservableCollection<string> { "elm", "oak", "pine" };
this.DataContext = vm;
}
XAML
<ItemsControl AlternationCount="{Binding Products.Count}"
ItemsSource='{Binding Products}'>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation='Vertical'>
<Label Margin="2" Width='200'
Content="{Binding (ItemsControl.AlternationIndex), RelativeSource={
RelativeSource TemplatedParent}}"
Foreground="#777" />
<TextBlock Text='{Binding}' />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Results
All above code work great :).
How to change Binding Path=Columns[0] to Binding Path=Columns[index_here]
It's in Width="{Binding Path=Columns[0].ActualWidth, ElementName=m_DataGrid}"

TextBlock1 is not declared. It may be inaccessible due to its protection level

As silly as this sounds I'm a little stumped at this one. Here's my XAML in a Win Phone 8 App:
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="Page" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
I've searched around but I don't know why I can't write code against the TextBlock1 control in code behind. When I type TextBlock1.Text= .... I get the error TextBlock1 is not declared. It may be inaccessible due to its protection level. But I can't see how it is private?
All I'm trying to do is add a textblock, assign some content to it, and then that selected value is passed across another page to perform relevant action.
In addition as soon as I remove it outside of the PhoneListSelector I can access it.
TextBlock1 is defined inside an ItemTemplate, anything defined a Template cannot be access directly as it will be created on runtime by the control.
You probably need to do binding on the TextBlock if you want to manipulate anything that the LongListSelector's DataContext has.
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" Text="{Binding Content"} HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
MainLongListSelector.DataContext = new List<TestViewModel>();
public class TestViewModel : INotifyPropertyChanged
{
//Assuming you've implemented the interface
private string _content;
public string Content { get { return _content; } { set { _content = value; NotifyOfPropertyChanged("Content"); } }
}
From here, you can try to access the selected value content and pass that to the next page.
var selectedItem = MainLongListSelector.SelectedItem as TestViewModel;
GoToNextPage(selectedItem.Content);
I strongly suggest to read MVVM design pattern and everything should be easy for you to implement, always remember UI is not DATA it's responsibility is only to show something that is passed through the ViewModel.

Using WPF/XAML to add dynamic controls to a form

I'm new to XAML/Wpf forms so maybe this project is a little outside of my ability. I would like to make a scheduler that essentially adds a bunch of "Jobs" to the form, each one has it's own abilities like click events and such but for the most part they are labels with a background and a set size.
Here is something like what I would like that I had made (with data removed) in Winforms, but it was very slow to add to the form. I was hoping some sort of databinding and user controls with xaml would help me out.
There will be a large number of these jobs, ideally I was thinking each row could be it's own usercontrol or each section (marked here as assembly cell).
I had some code that was able to place jobs onto the window, but there was no user control and no row or section labels. It looked like this in the xaml:
<Window.Resources>
<DataTemplate x:Key="Job">
<Label Content="{Binding}" Height ="100" Width="100" BorderThickness="1" BorderBrush="Black"/>
</DataTemplate>
<DataTemplate x:Key="wrkCenterPanel">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource job}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Width="Auto" Height="Auto" >
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
...
<Label Grid.Row="0" Grid.Column="0" Content="Production Scheduler" Width="Auto" Height="Auto" FontSize="40" FontWeight="Bold" HorizontalAlignment="Center" />
<ScrollViewer Grid.Row="1" Grid.Column="0" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="sched" ItemTemplate="{DynamicResource wrkCenterPanel}" />
</ScrollViewer>
In the code I just had a List(Of List(Of String)) And I added each row as a new list of strings and then binded it to sched. Is this even the right direction to be moving in? Any help at all would be greatly appreciated.
You do seem to be heading in the right direction, however I would suggest reading up on MVVM before you continue so that you can truly understand how DataBinding and the WPF template system will be of benefit. The Prism documentation on MVVM is a good place to start, but there are countless other places to learn about MVVM with a simple search.
The jist of it is that your DataTemplates are a good start, however you can go further. Rather than just using Strings and lists of strings, you can use CLR Objects (ViewModels, in MVVM terminology) and then define DataTemplates (Views) for visually representing those CLR Objects.
The result is that your XAML will look something like this (incomplete, but demonstrative):
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type vms:JobViewModel}">
<Label Content="{Binding Name}" Height ="100" Width="100" BorderThickness="1" BorderBrush="Black"/>
</DataTemplate>
<DataTemplate DataType="{x:Type WorkCenterViewModel}">
<ItemsControl ItemsSource="{Binding Jobs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Width="Auto" Height="Auto" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding WorkCenter}"/>
</Window>
And your CLR Objects will look something like this:
public class JobViewModel : ViewModel
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
public class WorkCenterViewModel : ViewModel
{
private ObservableCollection<JobViewModel> _jobs;
public ObservableCollection<JobViewModel> Jobs
{
get { return _jobs; }
}
}
When you define your DataTemplates without the x:Key property, but with a DataType property instead, it will automatically apply to any instances of that type it finds.

Zooming an item in Listbox/SurfaceListbox WPF

I am working on SurfaceListbox but I think the logic would apply to normal WPF listbox also.
I have the surfacelistbox with horizontal scroll enabled. It contains close to 20 items. The surfacelistbox is going to be placed in the center of the screen. Now when the user scrolls the listbox, the items move horizontally and based on the size of each item in the listbox, I have seen generally 3 items are visible at any given time on the screen.
Now what I want to do is, when the user stops scrolling and the 3 items are visible, I want to zoom in the center item i.e. basically enlarge it to highlight it.
Any pointers on how to implement such functionality in WPF would be great. Since the user doesnt make a selection when scrolling I could not use the selectionchanged event to know which one is the center item.
Place the SurfaceListBox in a Grid and bind ScaleTransform to a slider with a range from 1 to 5 centered in the Grid using RenderTransformOrigin="0.5,0.5".
The ItemsSource is set to an ObservableCollection; I include some definitions below for completeness to help others follow. I can provide more code if needed.
Here is the View:
<Window x:Class="SurfaceControls.MainWindow"
Icon="/Images/logo.gif"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Surface Toolkit Controls" Height="500" Width="600"
xmlns:my="http://schemas.microsoft.com/surface/2008" >
<Window.Resources>
<DataTemplate x:Key="EquipmentItemStyle">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Id}"/>
<TextBlock Text="{Binding Path=EquipmentName}"/>
<TextBlock Text="{Binding Path=EquipmentType}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid RenderTransformOrigin="0.5,0.5" Grid.Row="0">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform
ScaleY="{Binding Path=Value, ElementName=slider}"
ScaleX="{Binding Path=Value, ElementName=slider}"/>
</TransformGroup>
</Grid.RenderTransform>
<my:SurfaceListBox
ItemsSource="{Binding Path=Equipment, Mode=TwoWay}"
SelectedItem="{Binding Path=SelectedEquipment, Mode=TwoWay}"
ItemTemplate="{StaticResource ResourceKey=EquipmentItemStyle}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
VerticalAlignment="Stretch"
HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</my:SurfaceListBox>
</Grid>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<my:SurfaceSlider Ticks="5"
Width="100"
Minimum="1"
Interval="1"
Maximum="5"
x:Name="slider"
VerticalAlignment="Center"
Margin="4,4,4,4"/>
</StackPanel>
</Grid>
</Window>
Here this collection bound by the ListBox:
private ObservableCollection<Equipment> _equipment = new ObservableCollection<Equipment>();
public ObservableCollection<Equipment> Equipment
{
get
{
return _equipment;
}
set
{
_equipment = value;
}
}
And the defintion of the model:
public class Equipment
{
public int Id { get; set; }
public string EquipmentName { get; set; }
public string EquipmentType { get; set; }
}
Got useful information from these two links
http://social.msdn.microsoft.com/Forums/en-US/surfaceappdevelopment/thread/290f18c3-9579-4578-b215-45e6eb702470
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5d486826-9a72-4769-bd09-ff6977e16c30

Grid of Checkboxes in WPF

I have a WPF UserControl's datacontext tied to a class like this:
public class CheckBoxGridViewModel
{
public List<List<bool>> Checkboxes {get; set;}
}
I want it to display a grid of checkboxes. I'm assuming I can use an Itemscontrol, but don't know exactly how to do it with a dynamic set of columns for each row.
This question seems to answer mine, except the answer didn't give the example and I can't figure how to write it out.
So the question is, how would I write the xaml to display the checkboxes of the Checkboxes property so that they are lined up in a nice grid?
The outer list would be each row and the inner list would be each column of the row.
It's not clear if you're expecting each inner List to be the same size but if they are you can use a simple setup. Using nested ItemsControls with single row/column UniformGrids will give you an even distribution and automatically handle collections of any size without needing to setup Row and Column Definitions like with Grid:
<ItemsControl ItemsSource="{Binding Checkboxes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
See this question. The answer by Jobi Joy will let you present the 2D list but Binding won't work so you can't edit your values.
To be able to bind the values you can use a helper class like this
public static class BindableListHelper
{
public static List<List<Ref<T>>> GetBindable2DList<T>(List<List<T>> list)
{
List<List<Ref<T>>> refInts = new List<List<Ref<T>>>();
for (int i = 0; i < list.Count; i++)
{
refInts.Add(new List<Ref<T>>());
for (int j = 0; j < list[i].Count; j++)
{
int a = i;
int b = j;
refInts[i].Add(new Ref<T>(() => list[a][b], z => { list[a][b] = z; }));
}
}
return refInts;
}
}
This method uses this Ref class
public class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
Then you can set ItemsSource for the ItemsControl with
itemsControl.ItemsSource = BindableListHelper.GetBindable2DList<bool>(Checkboxes);
and the editing should work
Using the same code as Jobi Joy from the question I linked, you can change the Button in DataTemplate_Level2 to a CheckBox and bind IsChecked for it to Value instead (since it will point to the Ref class otherwise)
<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
<CheckBox IsChecked="{Binding Path=Value}" Height="15" Width="15" Margin="2"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Border HorizontalAlignment="Left" BorderBrush="Black" BorderThickness="2">
<ItemsControl x:Name="itemsControl" ItemTemplate="{DynamicResource DataTemplate_Level1}"/>
</Border>
</StackPanel>
Without setting the Content property for the CheckBox it'll look something like this
You might consider creating a class that exposes Row, Column, and Value properties, and binding to a collection of these. This lets you assign row and column positions using the method of your choice, and layout in a grid is very straightforward (once you understand how ItemsControl uses its ItemsPanel and ItemContainerStyle properties, of course):
<ItemsControl ItemsSource="{Binding Checkboxes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Value, Mode=TwoWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
How exactly do you want this grid arranged? This will influence which ItemsControl.ItemsPanel to use. A couple of ideas...
Use a UniformGrid, or the WPF Toolkit WrapPanel.

Resources