如何将WPF / XAML GridRow的高度设置为“自动”但仍将其限制为网格的最大可用高度?

时间:2016-05-07 09:00:26

标签: wpf xaml

我有一个GroupBox(包含一个ListBox)和一个Expander,每个都在Grid中各自的行中:

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


        <GroupBox Grid.Row="0" Header="My List">
            <ListBox>
                ...
            </ListBox>
        </GroupBox>


        <Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
            <Expander.Header>
                <TextBlock FontWeight="Bold">My Expander</TextBlock>
            </Expander.Header>

            <StackPanel Margin="5 5 5 5">
                <TextBlock TextWrapping="Wrap">
                    Lots<LineBreak />
                    and<LineBreak />
                    lots<LineBreak />
                    of<LineBreak />
                    lines.
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                    More <Run FontFamiliy="Courier">Stuff</Run> here.
                </TextBlock>
            </StackPanel>
        </Expander>
    <Grid>

通缉行为:

我希望GroupBox(带有ListBox)使用父级定义的Grid的所有可用空间(例如,父级是Window)减去(已关闭)Expander的大小。如果用户打开Expander,它应该让GroupBox缩小(甚至完全崩溃)并为Expander提供空间。

但是,我想将扩展器的高度限制为允许网格扩展而不会导致溢出的最大可用高度。如果扩展器的高度受到限制,它应该开始显示垂直滚动条。

当前行为:

使用我当前的XAML代码,扩展器将使网格溢出,即它将扩展到可用空间之外(因此也不会显示垂直滚动条。)

问题简而言之:

如何设置网格以使扩展器的高度受限于网格的最大可用高度?

2 个答案:

答案 0 :(得分:1)

第一个解决方案: 我能想到的简单解决方案是使用只读的TextBox代替Expander-&gt; TextBlock&amp;拥有VerticalScrollBarVisibility = Auto 以下是示例代码;

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition  />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="My List">
        <ListBox>
            ...
        </ListBox>
    </GroupBox>


    <Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
        <Expander.Header>
            <TextBlock FontWeight="Bold">My Expander</TextBlock>
        </Expander.Header>

        <StackPanel Margin="5 5 5 5">
            <TextBox TextWrapping="Wrap" Margin="0,0,0,30"  MaxHeight="290" HorizontalAlignment="Left" VerticalScrollBarVisibility="Auto" IsReadOnly="True" >
                <TextBox.Text>
                    Lorem ipsum dolor sit amet...
                    Very Very long text

                </TextBox.Text>
            </TextBox>
        </StackPanel>
    </Expander>
    </Grid>

你唯一需要注意的是TextBox的MaxHeight。 MaxHeight应该是(窗口高度 - 扩展器高度)。

第二个解决方案: 如果必须使用TextBlock,则可以将scrollViewer包装在TextBlock周围并将其MaxHeight设置为(窗口高度 - 扩展器高度)

首先:添加对XAML窗口的引用

xmlns:local="cld-namespace:AutoSizing"

第二个:像这样创建一个转换器实例。

<Window.Resources>
    <local:SizeModifierConverter x:Key="SizeModifierConverter"/>
</Window.Resources>

第三个​​:在ScrollViewer中使用Binding和Covnverter

       <ScrollViewer VerticalScrollBarVisibility="Auto" 
                      MaxHeight="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
                      Converter={StaticResource SizeModifierConverter}, ConverterParameter= -50}" >
            <StackPanel Margin="5 5 5 5">
                    <TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20"  HorizontalAlignment="Left" >
                       Long text with Run Linereak and hyperlinks...
                    </TextBlock>

                    <TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20"  HorizontalAlignment="Left" >
                       Long text with Run Linereak and hyperlinks...
                    </TextBlock>
            </StackPanel>
        </ScrollViewer>

转换器看起来像这样;

public class SizeModifierConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double ActualWidth;
        if(double.TryParse(value.ToString(), out ActualWidth))
        {
            double AdjustValue = 0;
            if (double.TryParse(parameter.ToString(), out AdjustValue))
            {
                return (ActualWidth + AdjustValue);
            }
        }

        return value;
    }

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

希望这会有所帮助!

答案 1 :(得分:1)

我提出了一个不需要任何代码隐藏的解决方案。我的解决方案使用DockPanel:

    <DockPanel>
        <Expander DockPanel.Dock="Bottom">
            <Expander.Header>
                <TextBlock FontWeight="Bold">My Expander</TextBlock>
            </Expander.Header>

            <ScrollViewer>
                <StackPanel Margin="5 5 5 5">
                    <TextBlock TextWrapping="Wrap">
                        Lots<LineBreak />
                        and<LineBreak />
                        lots<LineBreak />
                        of<LineBreak />
                        lines.
                    </TextBlock>
                    <TextBlock TextWrapping="Wrap">
                        More <Run FontFamiliy="Courier">Stuff</Run> here.
                    </TextBlock>
                </StackPanel>
            </ScrollViewer>
        </Expander>


        <GroupBox Header="My List" DockPanel.Dock="Top">
            <ListBox>
                ...
            </ListBox>
        </GroupBox>
    <Grid>