如何将 WPF/XAML GridRow 的高度设置为 Auto,但仍将其限制为 Grid 的最大可用高度?

问题描述 投票:0回答:3

我有一个 GroupBox(包含一个 ListBox)和一个 Expander,每个都位于网格内各自的行中:

    <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)使用父级(例如父级是 Window)定义的 Grid 的所有可用空间减去(关闭的)Expander 的大小。如果用户打开 Expander,它应该让 GroupBox 收缩(甚至完全折叠)并为 Expander 留出空间。

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

当前行为:

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

问题简而言之:

如何设置网格,以便将扩展器的高度限制为网格的最大可用高度?

wpf xaml
3个回答
2
投票

第一个解决方案: 我能想到的简单解决方案是用只读 TextBox 代替 Expander->TextBlock 并使用 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,您可以在 TextBlock 周围包裹一个scrollViewer,并将其 MaxHeight 设置为(窗口高度 - Expander 高度)

首先:添加对您的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
投票

我想出了一个不需要任何代码隐藏的解决方案。我的解决方案使用 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>

0
投票

我没有足够的观点发表评论,所以我将其发布在那里。 AnandShanbhag 提供的解决方案效果很好,只需要添加一个检查,看看 ActualWidth + AdjustValue 是否低于 0。如果是这种情况,则返回 0。在我的例子中,将窗口缩小到很小,由于负值,应用程序崩溃了。

    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))
            {
                var result = ActualWidth + AdjustValue;
                if (result < 0)
                {
                    result = 0;
                }
                return result;
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }
    }
© www.soinside.com 2019 - 2024. All rights reserved.