I'm trying to determine if there's a way to use an ItemsControl to group items in the ItemsSource into individual ItemsPanels. Specifically, I'm trying to create a view such that a collection of say, 8 items can be listed in grid-type fashion, like a UniformGrid, but with even results, and not empty cells.
While a UniformGrid with 8 items in the source would produce results like the following:
-------------------------------------
- +++++++++ - +++++++++ - +++++++++ -
-------------------------------------
- +++++++++ - +++++++++ - +++++++++ -
-------------------------------------
- +++++++++ - +++++++++ - ooooooooo -
-------------------------------------
(the last cell being empty)
I'm trying to produce results like so:
-------------------------------------
- +++++++++ - +++++++++ - +++++++++ -
-------------------------------------
- +++++++++ - +++++++++ - +++++++++ -
-------------------------------------
- +++++++++++++++ - +++++++++++++++ -
-------------------------------------
If I programmatically break it up, I can get the display easily by nesting like so:
<StackPanel Orientation="Horizontal">
<UniformGrid>
item 1
item 2
item 3
</UniformGrid>
<UniformGrid>
item 4
item 5
item 6
</UniformGrid>
<UniformGrid>
item 7
item 8
</UniformGrid>
</StackPanel>
But I'd like to acheive the results I want just through Xaml.
I found the way to do it by nesting an new ItemsControl in the DataTemplate of the one bound to the collection, and using a ValueConverter to convert the collection into an array of arrays.
<ItemsControl ItemsSource="{Binding MyCollection, Converter={StaticResource ArraySplitConverter}, ConverterParameter=3}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Title} />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the ValueConverter:
public class ArraySplitConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int param = System.Convert.ToInt16(parameter);
object[] coll = (object[])value;
ArrayList outer = new ArrayList();
ArrayList inner = new ArrayList();
for (int i = 0; i < coll.Length; i++)
{
inner.Add(coll[i]);
if (((i + 1) % param == 0) || (i == coll.Length - 1)) { outer.Add(inner); inner = new ArrayList(); }
}
return outer;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}