I'm trying to make a control to display custom list of checkboxes, like at the image:
My current implementation uses ItemsControl that has VariableSizedWrapGrid as an ItemsPanelTemplate. But it makes all items same sized... I can't figure out how to make cells sized by content just like in HTML table.
Unfortunatelly, there isn't such panel available by default.
If number of your items is static (or at least number of columns is static), you can use Grid
as ItemsPanelTemplate, and set Grid.Row
and Grid.Column
in ItemContainerStyle
trough converter.
Otherwise, you need to implement your custom panel by overriding ArrangeChildren and MeasureOverride methods. I have my custom panel that solves this issue. I can share it with you, if you won't find anything better
EDIT: I assume that you don't want to have all cells the same size. In that case you could use UniformGrid.
I have attached sample code using Grid + some codebehind. the codebehind is not violation of MVVM separation of concern, because there's pure view logic in codebehind.
<ItemsControl ItemsSource="{Binding ItemsSource}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Initialized="ItemsPanel_Initialized" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<EventSetter Event="Loaded" Handler="Item_Loaded" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
private void ItemsPanel_Initialized(object sender, EventArgs e)
{
//generate row and column definitions
for (int i = 0; i < ViewModel.ColumnsCount; i++)
{
((Grid)sender).ColumnDefinitions.Add(new ColumnDefinition{ Width = new GridLength()});
}
for (int i = 0; i <= ViewModel.ItemsSource.Count / ViewModel.ColumnsCount; i++)
{
((Grid)sender).RowDefinitions.Add(new RowDefinition{ Height = new GridLength() });
}
}
private void Item_Loaded(object sender, RoutedEventArgs e)
{
var itemContainer = (FrameworkElement) sender;
var itemsControl = ItemsControl.ItemsControlFromItemContainer(itemContainer);
var itemIndex = itemsControl.ItemContainerGenerator.IndexFromContainer(itemContainer);
Grid.SetColumn(itemContainer, itemIndex % ViewModel.ColumnsCount);
Grid.SetRow(itemContainer, itemIndex / ViewModel.ColumnsCount);
}