WPF Grid - Auto-sizing with minimum height constraints

寵の児 提交于 2019-12-24 00:54:22

问题


Background

I need a grid with the following layout properties:

  1. 4 rows: header, main content, sub-content, footer
  2. The header is static content which isn't really affected by resize
  3. The main content needs to fill up all available space, with a minimum height of 180
  4. The sub-content is a RTB that can shrink and grow. This sub-content can eat up some of the main-contents space, but should always leave 180 pixels for the main-content. The sub-content should ideally only take up the minimum amount of area it needs. If there isn't much room left in the grid, the RTB should stop growing and instead enable its internal scrollviewer.
  5. The footer is like the header, static content unaffected by resize

The problem

The sub-content (RTB) isn't auto-sizing itself to fit within the remaining space, nor is the vertical scroll-bar being enabled. This is causing anything below the main content to clip outside of the window.

Question

How can I get the RichTextBox to shrink so that the footer is shown, allowing the user to scroll through the hidden RichTextBox content, while simultaneously allowing the RichTextBox to expand if the user stretches the window?

Below you will find a SSCCE which demonstrates what I'm trying to achieve and the issues that it's causing:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        MinWidth="200" MinHeight="300" Width="200" Height="300">

    <Grid>

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

        <TextBlock Grid.Row="0" Text="Header" HorizontalAlignment="Center"/>

        <Rectangle Grid.Row="1" Fill="Red"/>

        <RichTextBox Grid.Row="2"
                     VerticalScrollBarVisibility="Visible"
                     Height="Auto"
                     Margin="0,5,0,0"
                     VerticalAlignment="Stretch"
                     BorderBrush="#FF818181"
                     BorderThickness="0.5"
                     Background="#FFEEEEEE"
                     FontSize="14">
            <FlowDocument>
                <List>
                    <ListItem>
                        <Paragraph>Lorem</Paragraph>
                        <Paragraph>IpSum</Paragraph>
                        <Paragraph>Lorem</Paragraph>
                        <Paragraph>IpSum</Paragraph>
                    </ListItem>
                </List>
            </FlowDocument>
        </RichTextBox>

        <TextBlock Grid.Row="3" Text="Footer" HorizontalAlignment="Center"/>

    </Grid>
</Window>

Here is an image of the window when it's at its minimum size:

Here is an image of the window when it has been stretched to show all:

Extra information

I know that if I set the sub-content RowDefinition to * then the RichTextBox works fine, except for the fact it takes too much room when the window is expanded. I need this area to take as much room as Auto while behaving like *.


回答1:


Divide and conquer

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        MinWidth="200" MinHeight="300" Width="200" Height="300">
    <Window.Resources>
        <local:HeightConverter x:Key="HeightConverter" />
    </Window.Resources>

    <!--MainGrid-->
    <Grid Name="grid">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

    <!--AlignmentGrid-->
        <Grid Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*" MinHeight="180"/>
                <RowDefinition Height="Auto">
                </RowDefinition>
            </Grid.RowDefinitions>
            <TextBlock Name="head" Grid.Row="0" Text="Header" HorizontalAlignment="Center"/>
            <Rectangle Name="rect" Grid.Row="1" Fill="Red"/>
            <RichTextBox Grid.Row="2"
                         VerticalScrollBarVisibility="Visible"
                         Margin="0,5,0,0"
                         VerticalAlignment="Stretch"
                         BorderBrush="#FF818181"
                         BorderThickness="0.5"
                         Background="#FFEEEEEE"
                         FontSize="14">
                <RichTextBox.MaxHeight>
                    <MultiBinding Converter="{StaticResource HeightConverter}">
                        <Binding ElementName="grid" Path="ActualHeight"/>
                        <Binding ElementName="head" Path="ActualHeight"/>
                        <Binding ElementName="rect" Path="ActualHeight"/>
                        <Binding ElementName="foot" Path="ActualHeight"/>
                    </MultiBinding>
                </RichTextBox.MaxHeight>
                <FlowDocument>
                    <List>
                        <ListItem>
                            <Paragraph>Lorem</Paragraph>
                            <Paragraph>IpSum</Paragraph>
                            <Paragraph>Lorem</Paragraph>
                            <Paragraph>IpSum</Paragraph>
                        </ListItem>
                    </List>
                </FlowDocument>
            </RichTextBox>
        </Grid>

    <!--Footer-->
        <TextBlock Name="foot" Grid.Row="1" Text="Footer" HorizontalAlignment="Center"/>
    </Grid>
</Window>

The Converter:

public class HeightConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double gridHeight = (double)values[0];
        double headHeight = (double)values[1];
        double rectHeight = (double)values[2];
        double footHeight = (double)values[3];

        return gridHeight - headHeight - rectHeight - footHeight;
    }

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

Note that for the Converter to give the desired result, the height of the MainGrid may not exceed the height of the content in the Window.



来源:https://stackoverflow.com/questions/37810682/wpf-grid-auto-sizing-with-minimum-height-constraints

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!