Search code examples
wpfwindows-store-apps

Windows store app ItemsControl HTML-table-like behavior


I'm trying to make a control to display custom list of checkboxes, like at the image:

enter image description here

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.


Solution

  • 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);
    }