Marius
Marius

Reputation: 9654

Wpf: Grid: How can i share column/row height width?

I have a grid with 3 columns and 5 rows:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Label Grid.Row="0" Grid.Column="0">Gas Volume Fraction</Label>
    <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=GasVolumeFraction}" MinWidth="40"></TextBox>
    <Label Grid.Row="0" Grid.Column="2">-</Label>

    <Label Grid.Row="1" Grid.Column="0">Density</Label>
    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Density}" MinWidth="40"></TextBox>
    <Label Grid.Row="1" Grid.Column="2">kg/m3</Label>

    <Label Grid.Row="2" Grid.Column="0" Content="Curve speed" Style="{StaticResource curveSpeed}" ></Label>
    <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Density}" Style="{StaticResource curveSpeed}" MinWidth="40"></TextBox>
    <Label Grid.Row="2" Grid.Column="2" Style="{StaticResource curveSpeed}">rpm</Label>

    <WrapPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3">
        <RadioButton>Delta pressure</RadioButton>
        <RadioButton>Head</RadioButton>
    </WrapPanel>

    <WrapPanel Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3">
        <RadioButton>Efficiency</RadioButton>
        <RadioButton>Power</RadioButton>
        <RadioButton>Torque</RadioButton>
    </WrapPanel>

</Grid>

The textboxes and radiobuttons have different space requirements, which makes the rows render with different heights based on their content. How can I make the rows evenly sized, but not larger than whats necessary? In other words: I want the same height as setting Height="Auto" for a row which contains a textbox (the biggest element in my grid) and then use that height for all the rows.

Upvotes: 8

Views: 23502

Answers (4)

Dusseldorf
Dusseldorf

Reputation: 521

There's actually a very simple solution to this problem, using the SharedSizeScope mentioned here.

<Grid Grid.IsSharedSizeScope="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" SharedSizeGroup="groupName" />
        <RowDefinition Height="Auto" SharedSizeGroup="groupName" />
        <RowDefinition Height="Auto" SharedSizeGroup="groupName" />
    </Grid.RowDefinitions>
    ...
</Grid>

Just make sure you set Grid.IsSharedSizeScope to true, and make sure that each RowDefinition has the same SharedSizeGroup, and the rows should be auto and equally sized. This works for columns as well.

Upvotes: 39

user8276908
user8276908

Reputation: 1061

My problem is similar to the above question but slightly different because neither the IsSharedSizeScope approach solved it for me nor the Binding with ActualWidth. So, I post another solution hoping someone finds this useful. So, here is the problem I needed to solve:

I have an application in which I have a control with a split view - see blue part below - and while I like to have a GridSplitter in the middle of the display I want to implement the blue part in a seperate control while the part on top of it should be implemented in a seperated assembly: enter image description here ...but the GridSplitter should go all the way across the main view and connect both areas without the user having an idea about the actual seperation. I accomplished this by setting the columns width whenever the TopSplitter or the MainSplitter is dragged.

This approach has no performance penality and works with '*' sized columns.

It turnes out that synchronizing two or more GridSplitters (as in this case) requires us in fact to synchronize the columns width that are 'resized' by the GridSplitter. Drag on the Top- or MainSplitter and you'll see that the other area resizes as if this was one splitter :-)

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid Grid.Row="0" Margin="3,3,3,0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" Name="TopColumnA"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*" Name="TopColumnB"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Grid.Row="0"
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                   Background="AntiqueWhite"
                   Margin="0,0,3,3"
                   />

        <GridSplitter
            Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Name="TopSplitter"
            HorizontalAlignment="Stretch"
            Background="Gray" Width="6"
            DragCompleted="GridSplitter_DragCompleted"
            DragDelta="MainSplitter_DragDelta"
            />

        <TextBlock Grid.Column="2" Grid.Row="0"
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                   Background="AntiqueWhite"
                   Margin="3,0,0,3"
                   />
    </Grid>

    <Grid Grid.Row="1" Margin="3,0,3,3">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" Name="MainColumnA"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*" Name="MainColumnB"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Grid.Row="0"
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                   Background="Aqua"
                   Margin="0,0,3,0"
                   />

        <GridSplitter
            Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Name="MainSplitter"
            HorizontalAlignment="Stretch"
            Background="Black" Width="6"
            DragCompleted="GridSplitter_DragCompleted"
            DragDelta="MainSplitter_DragDelta"
            />

        <TextBlock Grid.Column="2" Grid.Row="0"
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                   Background="Aqua"
                   Margin="3,0,0,0"
                   />
    </Grid>
</Grid>

...and here is the required code behind:

private void GridSplitter_DragCompleted(object sender, DragCompletedEventArgs e)
{
    if (sender == MainSplitter)
    {
        TopColumnA.Width = MainColumnA.Width;
        TopColumnB.Width = MainColumnB.Width;
    }
    else
    {
        if (sender == TopSplitter)
        {
            MainColumnA.Width = TopColumnA.Width;
            MainColumnB.Width = TopColumnB.Width;
        }
    }
}

private void MainSplitter_DragDelta(object sender, DragDeltaEventArgs e)
{
    if (sender == MainSplitter)
    {
        TopColumnA.Width = MainColumnA.Width;
        TopColumnB.Width = MainColumnB.Width;
    }
    else
    {
        if (sender == TopSplitter)
        {
            MainColumnA.Width = TopColumnA.Width;
            MainColumnB.Width = TopColumnB.Width;
        }
    }
}

Upvotes: 0

Quartermeister
Quartermeister

Reputation: 59129

Ideally you would use rows with star sizing as you have and set the Grid to VerticalAlignment="Top", but unfortunately star sizing doesn't work when the grid sizes to its content.

Instead of using a single Grid, use a UniformGrid for the vertical layout with nested Grid controls for horizontal layout. You can set a SharedSizeScope on the columns in the inner grids so that the column sizing is shared between them.

<UniformGrid Rows="5" VerticalAlignment="Top" Grid.IsSharedSizeScope="True">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="A"/>
            <ColumnDefinition SharedSizeGroup="B"/>
            <ColumnDefinition SharedSizeGroup="C"/>
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0">Gas Volume Fraction</Label>
        <TextBox Grid.Column="1" Text="{Binding Path=GasVolumeFraction}" MinWidth="40"></TextBox>
        <Label Grid.Column="2">-</Label>
    </Grid>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="A"/>
            <ColumnDefinition SharedSizeGroup="B"/>
            <ColumnDefinition SharedSizeGroup="C"/>
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0">Density</Label>
        <TextBox Grid.Column="1" Text="{Binding Path=Density}" MinWidth="40"></TextBox>
        <Label Grid.Column="2">kg/m3</Label>
    </Grid>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="A"/>
            <ColumnDefinition SharedSizeGroup="B"/>
            <ColumnDefinition SharedSizeGroup="C"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Column="0" Content="Curve speed" Style="{StaticResource curveSpeed}"></Label>
        <TextBox Grid.Column="1" Text="{Binding Path=Density}" Style="{StaticResource curveSpeed}" MinWidth="40"></TextBox>
        <Label Grid.Column="2" Style="{StaticResource curveSpeed}">rpm</Label>
    </Grid>
    <WrapPanel>
        <RadioButton>Delta pressure</RadioButton>
        <RadioButton>Head</RadioButton>
    </WrapPanel>
    <WrapPanel>
        <RadioButton>Efficiency</RadioButton>
        <RadioButton>Power</RadioButton>
        <RadioButton>Torque</RadioButton>
    </WrapPanel>
</UniformGrid>

Upvotes: 15

Eugene Cheverda
Eugene Cheverda

Reputation: 8930

You can use binding to ActualWidth and ActualHeight of your biggest TextBlock.

    <Grid x:Name="grid" ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="{Binding Path=ActualHeight, ElementName=biggestTB}"/>
            <RowDefinition Height="{Binding Path=ActualHeight, ElementName=biggestTB}"/>                        
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="{Binding Path=ActualWidth, ElementName=biggestTB}"/>
            <ColumnDefinition Width="{Binding Path=ActualWidth, ElementName=biggestTB}"/>                        
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" x:Name="biggestTB" Text="biggest textblock content" TextWrapping="Wrap"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Text="content" TextWrapping="Wrap"/>
    </Grid>

Upvotes: 2

Related Questions