Wpf: Сетка: Как я могу поделиться шириной столбца / высоты строки?

У меня есть сетка с 3 столбцами и 5 рядами:

<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>

Для текстовых полей и радиокнопок предъявляются разные требования к пространству, поэтому строки отображаются с разной высотой в зависимости от их содержимого. Как сделать так, чтобы строки были одинакового размера, но не больше, чем нужно? Другими словами: я хочу получить ту же высоту, что и параметр Height="Auto" для строки, которая содержит текстовое поле (самый большой элемент в моей сетке), а затем использовать эту высоту для всех строк.

3 ответа

Решение

В идеале вы должны использовать строки со звездообразным размером и установить для Grid значение VerticalAlignment="Top", но, к сожалению, размер звезды не работает, когда размер сетки соответствует ее содержанию.

Вместо использования одной сетки, используйте UniformGrid для вертикальной компоновки с вложенными элементами управления Grid для горизонтальной компоновки. Вы можете установить SharedSizeScope для столбцов во внутренних сетках, чтобы размеры столбцов были общими для них.

<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>

Я знаю, что это старый вопрос, но я отвечу за всех, кто сталкивается с этим, когда гуглит.

На самом деле существует очень простое решение этой проблемы с использованием SharedSizeScope, упомянутого Quartermeister.

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

    ...
</Grid>

Просто убедитесь, что для Grid.IsSharedSizeScope установлено значение true, и убедитесь, что у каждого RowDefinition есть одна и та же SharedSizeGroup, а строки должны быть автоматически и иметь одинаковый размер. Это работает и для столбцов.

Вы можете использовать привязку к ActualWidth и ActualHeight вашего самого большого 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>

Моя проблема похожа на вопрос выше, но немного отличается, потому что ни IsSharedSizeScope подход решил это для меня, ни Binding с ActualWidth. Итак, я публикую другое решение, надеясь, что кто-то найдет это полезным. Итак, вот проблема, которую мне нужно было решить:

У меня есть приложение, в котором у меня есть элемент управления с разделенным видом - см. Синюю часть ниже - и хотя мне нравится иметь GridSplitter в середине экрана, я хочу реализовать синюю часть в отдельном элементе управления, в то время как часть сверху это должно быть реализовано в отдельной сборке: ... но GridSplitter должен пройти весь основной вид и соединить обе области, чтобы у пользователя не было представления о фактическом разделении. Я сделал это, установив ширину столбцов всякий раз, когда TopSplitter или MainSplitter тащат

Этот подход не требует снижения производительности и работает со столбцами размера "*".

Оказывается, что синхронизация двух или более GridSplitters (как в этом случае) фактически требует от нас синхронизации ширины столбцов, которые "изменяются" с помощью GridSplitter. Перетащите на Top- или MainSplitter, и вы увидите, что другая область изменяет размеры, как если бы это был один сплиттер:-)

<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>

... и вот необходимый код:

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;
        }
    }
}
Другие вопросы по тегам