Search code examples
wpfgridheightmultibinding

Grid.Row Dynamic Resize


I am using MultiBinding and a MultiValueConverter on a Grid in order to set the MaxHeight of each Grid.Row according to the ActualHeight of all Grid.Rows.

               <RowDefinition x:Name="grdRow1" Height="Auto" >
                    <RowDefinition.MaxHeight>
                        <MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                            <Binding Path="ActualHeight" ElementName="grdRow1" />
                            <Binding Path="ActualHeight" ElementName="grdRow2" />
                            <Binding Path="ActualHeight" ElementName="grdRow3" />
                            <Binding Path="ActualHeight" ElementName="grdRow4" />
                            <Binding Path="ActualHeight" ElementName="grdRow5" /> 
                        </MultiBinding>
                    </RowDefinition.MaxHeight>
                </RowDefinition>

MultiConverter:

public class AvailableHeightConverter : IMultiValueConverter
{
    public double PanelHeight { get; set; }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null)
            return Binding.DoNothing;

        double currentHeight = 0d;
        double availableHeight = 0d;

        foreach (object value in values)
        {
            currentHeight += (double)value;
        }

        availableHeight = PanelHeight - currentHeight;

        if (availableHeight < 0)
            return Binding.DoNothing;

        return availableHeight;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

UserControl.Resources:

<cvc:AvailableHeightConverter x:Key="CalculateMaxHeightConverter" PanelHeight="1080" />

My problem (a dummy one) is that i cannot figure out how to UpdateSourceTrigger whenever the ActualHeight of a Grid.Row is being changed.


Solution

  • OK. After experimenting with various senarios i ended up that Binding row's ActualHeight doesn't notify MultiBinding for changes. Also what @christoph noticed (2.) was very helpful. So i ended up binding TextBox's ActualWidth as shown below:

    for Row 1

                <RowDefinition x:Name="grdRow1" Height="Auto" >
                <RowDefinition.MaxHeight>
                    <MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}">
                        <Binding Path="ActualHeight" ElementName="txtBox2" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox3" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox4" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox5" Mode="OneWay" /> 
                    </MultiBinding>
                </RowDefinition.MaxHeight>
            </RowDefinition>
    

    for Row 2

            <RowDefinition x:Name="grdRow2" Height="Auto" >
                <RowDefinition.MaxHeight>
                    <MultiBinding Converter="{StaticResource CalculateMaxHeightConverter}">
                        <Binding Path="ActualHeight" ElementName="txtBox1" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox3" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox4" Mode="OneWay" />
                        <Binding Path="ActualHeight" ElementName="txtBox5" Mode="OneWay" /> 
                    </MultiBinding>
                </RowDefinition.MaxHeight>
            </RowDefinition>
    

    and subtract the Height of one row from the PanelHeight (of AvailableHeightConverter).

    <cvc:AvailableHeightConverter x:Key="CalculateMaxHeightConverter" PanelHeight="1028" />
    

    (Used to be 1080 (-52 MinHeight of a Row)