Search code examples
c#wpfuniformgrid

Adjust uniform grid to number of children


I want to make a uniformGrid in wpf.

When I have 1 child, I want it to fill the grid, 2 childs I want 2 columns and when I have 3 or 4 children I want to have 2 rows and 2 columns.

So I've made a converter that checks how many children there are in the grid and based on that decides the number of rows / columns:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows;
using System.Globalization;

namespace UserControlSolution.Converter
{
    [ValueConversion(typeof(int), typeof(int))]
    public class CountToDimensionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int itemsCount = (int)value;
            int dimensionLength = 1;
            if (itemsCount > 0)
            {   
                if (string.Equals((string)parameter, "Rows", StringComparison.OrdinalIgnoreCase))
                {
                    switch(itemsCount)
                    {
                        case 1: 
                        case 2: dimensionLength = 1;
                            break;
                        case 3: 
                        case 4: dimensionLength = 2;
                            break;
                    }
                }

                if (string.Equals((string)parameter, "Columns", StringComparison.OrdinalIgnoreCase))
                {
                    switch(itemsCount)
                    {
                        case 1: dimensionLength = 1;
                            break;
                        case 2: 
                        case 3: 
                        case 4: dimensionLength = 2;
                            break;
                    }
                }
            }

            return dimensionLength;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

This is my xaml:

<customGridView:MyUniformGrid x:Name="AlarmButtonGrid" Margin="0,10" Grid.Row="2" Width="{Binding ActualWidth, ElementName=AlarmPictureBox}"
        Rows="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=Rows}" 
        Columns="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=Columns}"> 

       <Button x:Name="Button1" Content="Sluit" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5" />
       <Button x:Name="Button2" Content="Verbergen" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
       <Button x:Name="Button3" Visibility="Collapsed" Content="Extra rij" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
       <Button x:Name="Button4" Visibility="Collapsed" Content="Extra rij" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
</customGridView:MyUniformGrid>

Binding to Children.Count

I found in this post that I had to make a custom UniformGrid so that the Children.count of the grid actually works, so I did that.

This code all works, but I have one problem left.

These buttons can be dynamically made visibile or collapsed, and when a button is collapsed I don't want them to matter for the number of rows. When button 3 & 4 are collapsed I don't want to have a 2nd row.

Any idea how to achieve this?


Solution

  • In your MyUniformGrid class, just add a new property:

    public int VisibleCount
    {
        get { return Children.OfType<UIElement>().Count(c => c.Visibility == 
                  Visibility.Visible); }
    }
    

    ... and bind to that instead:

    <customGridView:MyUniformGrid x:Name="AlarmButtonGrid" Margin="0,10" Grid.Row="2" 
        Width="{Binding ActualWidth, ElementName=AlarmPictureBox}" Rows="{Binding 
        RelativeSource={RelativeSource Self}, Path=VisibleCount, Converter={
        StaticResource CountToDimensionConverter}, ConverterParameter=Rows}" Columns="{
        Binding RelativeSource={RelativeSource Self}, Path=VisibleCount, Converter={
        StaticResource CountToDimensionConverter}, ConverterParameter=Columns}">                    
        <Button x:Name="Button1" Content="Sluit" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5" />
        <Button x:Name="Button2" Content="Verbergen" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
        <Button x:Name="Button3" Visibility="Collapsed" Content="Extra rij" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
        <Button x:Name="Button4" Visibility="Collapsed" Content="Extra rij" Height="35" Style="{StaticResource CustomButtonStyle}" Margin="5"/>
    </customGridView:MyUniformGrid>
    

    The only point to note is that you may need to call the INotifyPropertyChanged.PropertyChanged event whenever you add or remove items from the Grid.Children collection... alternatively, you could implement this as a DependencyProperty instead.