如何在WPF中将高度设置为自动时使scrollviewer工作?

tet*_*ete 16 wpf xaml autosize scrollviewer uwp-xaml

我已经了解到,如果将网格行的高度ScrollViewer设置为Auto,则垂直滚动条将不会生效,因为它的实际大小ScrollViewer可能大于视线中的高度.因此,为了使滚动条工作,我应该将高度设置为固定数字或星形高度

但是,我现在有了这个要求,我有两个不同的视图驻留在两个网格行中,并且我有一个切换按钮可以在这两个视图之间切换:当显示一个视图时,另一个视图隐藏/消失.所以我定义了两行,两个高度都设置为Auto.我绑定的每一行中的布尔属性视图的可视性从我的视图模型(一个是从转换TrueVisible从和其他TrueCollapsed.我们的想法是,当一个视图的能见度Collapsed,网格行的高度/视图将被改变自动为0.

视图显示/隐藏工作正常.但是,在一个视图中我有一个ScrollViewer,正如我所提到的,当行高设置为时,它不起作用Auto.任何人都能告诉我如何在仍然ScrollViewer自动工作的同时满足这样的要求吗?我想我可以在代码隐藏中设置高度.但由于我使用的是MVVM,因此需要额外的通信/通知.有没有更简单的方法呢?

Con*_*ngo 23

在MVVM,这对我的工作方式是的高度绑定ScrollViewerActualHeight父控件(这是类型总是UIElement).

ActualHeight是一个只读属性,仅在控件绘制到屏幕上后才设置.如果调整窗口大小,它可能会改变.

<StackPanel>
    <ScrollViewer Height="{Binding Path=ActualHeight, 
           RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}">
        <TextBlock Text=Hello"/>
    </ScrollViewer>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

但是,如果父控件具有无限高度呢?

如果父控件具有无限高度,那么我们就会遇到更大的问题.我们必须不断设置所有父母的身高,直到我们击中一个非无限高度的控件.

Snoop绝对是非常宝贵的:

在此输入图像描述

如果任何XAML元素的"Height"是0或者NaN,您可以使用以下方法之一将其设置为某个值:

  • Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}"
  • VerticalAlignment="Stretch"
  • Height="Auto"

提示:使用VerticalAlignment="Stretch",如果你的孩子Grid有一个<RowDefinition Height="*">,而Binding RelativeSource...在其他地方,如果不工作.


如果您有兴趣,这是我之前尝试解决此问题的所有尝试:

附录A:以前的尝试1

也可以用这个:

Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"
Run Code Online (Sandbox Code Playgroud)

附录B:以前的尝试2

有用信息:参见WPF - 自动高度与MaxHeight的组合.

如果似乎没有任何工作,那可能是因为ActualHeight父级的是0(因此没有任何可见)或巨大的(因此滚动查看器永远不需要出现).如果存在深度嵌套的网格,并且滚动查看器位于底部,则这是一个更大的问题.

  • 使用Snoop查找ActualHeight父级StackPanel.在属性中,按单词过滤"Actual",返回ActualHeightActualWidth.
  • 如果ActualHeight为零,使用它给它一个最小高度MinHeight,所以我们至少可以看到一些东西.
  • 如果ActualHeight它太大以至于它离开屏幕的边缘(即16,000),使用它给它一个合理的最大高度MaxHeight,所以滚动条会出现.

滚动条出现后,我们可以进一步清理它:

  • 绑定HeightStackPanelGridActualHeight母公司.

最后,把它ScrollViewer放在里面StackPanel.

附录C:以前的尝试3

事实证明,这有时会失败:

Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"
Run Code Online (Sandbox Code Playgroud)

原因?绑定失败,高度为零,没有任何东西可见.如果我们绑定到不可访问的元素,绑定可能会失败.如果我们进入up可视树,然后down到叶节点(例如,直到父网格,然后到达ActualHeight连接到该网格的行),绑定将失败.这就是为什么绑定到ActualWidth一个RowDefinition简单的无法工作.

附录D:以前的尝试4

我最终得到了这个工作,确保Height=Auto从我们的所有父元素到<Grid>UserControl中的第一个元素.


Mac*_*ski 14

如果可以的话,Auto将高度改为*.

例:

    <Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="525">
    <StackPanel Orientation="Horizontal"  Background="LightGray">

        <Grid Width="100">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="_scroll1">
                <Border Height="300" Background="Red" />
            </ScrollViewer>
            <TextBlock Text="{Binding ElementName=_scroll1, Path=ActualHeight}" Grid.Row="1"/>
        </Grid>

        <Grid Width="100">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
                <ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="_scroll2">
                    <Border Height="300" Background="Green" />
                </ScrollViewer>
            <TextBlock Text="{Binding ElementName=_scroll2, Path=ActualHeight}" Grid.Row="1"/>
        </Grid>
    </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)