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

如何使scrollviewer在WPF中将高度设置为自动时工作?,wpf,xaml,uwp-xaml,scrollviewer,autosize,Wpf,Xaml,Uwp Xaml,Scrollviewer,Autosize,我了解到,如果将ScrollViewer所在的网格行的高度设置为Auto,垂直滚动条将不会生效,因为ScrollViewer的实际大小可能大于可见高度。因此,为了使滚动条工作,我应该将高度设置为固定数字或星形高度 但是,我现在有这个要求,我有两个不同的视图位于两个网格行中,我有一个切换按钮在这两个视图之间切换:当一个视图显示时,另一个视图隐藏/消失。所以我定义了两行,两个高度都设置为Auto。我将每行视图的可见性绑定到ViewModel中的布尔属性(一个从True转换为Visible,另一个从T

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

但是,我现在有这个要求,我有两个不同的视图位于两个网格行中,我有一个切换按钮在这两个视图之间切换:当一个视图显示时,另一个视图隐藏/消失。所以我定义了两行,两个高度都设置为
Auto
。我将每行视图的可见性绑定到ViewModel中的布尔属性(一个从
True
转换为
Visible
,另一个从
True
转换为
Collapsed
。其思想是当一个视图的可见性为
Collapsed
时,网格行/视图的高度将自动更改为0


视图show/hidden运行良好。但是,在一个视图中,我有一个
ScrollViewer
,正如我所提到的,当行高度设置为
Auto
时,它不起作用。有人能告诉我如何在仍然让
ScrollViewer
自动工作的情况下满足这些要求吗?我想我可以在代码中设置高度ind.但由于我使用的是MVVM,因此需要额外的通信/通知。有没有更直接的方法来实现这一点?

如果可以的话,将高度从
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>


< /代码> 你可以在ScLoVIEVIEW上设置一个固定的高度,但是你必须考虑到你的网格的第二行也会有这个高度,因为行的第一个孩子将是ScRelVIEW和行的高度是Autoor,或者你把ScRelVIEW的高度绑定到你的布局中的另一个控件上。我们不知道你的布局看起来如何。


最后,如果您不喜欢这两个选项,只需按照swiszcz的建议将行的高度设置为*或hack wpf编写您自己的自定义面板,该面板将能够在每个平行宇宙或类似的情况下布局所有可能的内容。:)

在MVVM中,我的工作方式是将
ScrollViewer
的高度绑定到父控件的
ActualHeight
(始终为
UIElement
类型)

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

<StackPanel>
    <ScrollViewer Height="{Binding Path=ActualHeight, 
           RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}">
        <TextBlock Text=Hello"/>
    </ScrollViewer>
</StackPanel>
附录B:以前的尝试2 有用信息:请参阅

如果什么都不起作用,那可能是因为父级的
实际高度
要么是0(因此没有可见的内容)要么是巨大的(因此scrollviewer永远不需要出现)。如果网格嵌套较深,且scrollviewer位于底部,则问题更大

  • 使用Snoop查找父级
    StackPanel
    ActualHeight
    。在属性中,按单词
    “Actual”
    进行过滤,这将返回
    ActualHeight
    ActualWidth
  • 如果
    实际高度
    为零,则使用
    最小高度
    给它一个最小高度,这样我们至少可以看到一些东西
  • 如果
    实际高度
    太大以至于超出屏幕边缘(即16000),请使用
    最大高度
    为其设定一个合理的最大高度,这样就会出现滚动条
滚动条出现后,我们可以进一步清理:

  • 堆叠面板
    网格
    高度
    绑定到父级的
    实际高度
最后,将一个
ScrollViewer
放在
StackPanel

附录C:以前的尝试3 事实证明,这有时会失败:

Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"
原因?如果绑定失败,那么高度将为零,并且什么也看不到。如果绑定到不可访问的元素,则绑定可能失败。如果我们向上移动可视化树,然后向下移动叶节点,则绑定将失败(例如,向上到父网格,然后向下到附加到该网格的行的
实际高度
)。这就是为什么绑定到
行定义的
实际宽度
根本不起作用的原因

附录D:先前的尝试4
最后,我通过确保所有父元素的
Height=Auto
都是用户控件中的第一个
元素来实现这一点。

我发现,您必须将您的
ScrollViewer
放在一个具有
Height=Auto
的容器中,或者您可以得到其父元素的
高实际大小e
并将其应用于该容器

在我的例子中,我有
UserControl
like

  <Grid Margin="0,0,0,0" Padding="0,2,0,0">
                    <ScrollViewer Height="Auto" ZoomMode="Disabled" IsVerticalScrollChainingEnabled="True"  VerticalAlignment="Top"
                     HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Disabled"
                     VerticalScrollMode="Enabled" VerticalScrollBarVisibility="Visible"> 
                        <ListView  ItemsSource="{x:Bind PersonalDB.View, Mode=OneWay}" x:Name="DeviceList"
                           ScrollViewer.VerticalScrollBarVisibility="Hidden" 
                    ItemTemplate="{StaticResource ContactListViewTemplate}"
                    SelectionMode="Single"
                    ShowsScrollingPlaceholders="False"
                    Grid.Row="1" 
                    Grid.ColumnSpan="2"
                    VerticalAlignment="Stretch"
                    BorderThickness="0,0,0,0"
                    BorderBrush="DimGray">
                            <ListView.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <ItemsStackPanel AreStickyGroupHeadersEnabled="False" />
                                </ItemsPanelTemplate>
                            </ListView.ItemsPanel>
                            <ListView.GroupStyle>
                                <GroupStyle>
                                    <GroupStyle.HeaderTemplate>
                                        <DataTemplate x:DataType="local1:GroupInfoList">
                                            <TextBlock Text="{x:Bind Key}" 
                                       Style="{ThemeResource TitleTextBlockStyle}"/>
                                        </DataTemplate>
                                    </GroupStyle.HeaderTemplate>
                                </GroupStyle>
                            </ListView.GroupStyle>
                        </ListView>
                    </ScrollViewer>
                </Grid> 
请注意,
行的
高度
*

当我填充
ContentControl
时,我在
Loaded
事件中使用此代码

  UIControlContainer.Content = new UIDeviceSelection() { 
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
Height = UIControlContainer.ActualHeight,
Width = UIControlContainer.ActualWidth
};
而且当
ContentControl
更改其大小时,您必须更新
UserControl
的大小

 UIControlContainer.SizeChanged += UIControlContainer_SizeChanged;

 private void UIControlContainer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (UIControlContainer.Content != null)
            {
                if (UIControlContainer.Content is UserControl)
                {
                    (UIControlContainer.Content as UserControl).Height = UIControlContainer.ActualHeight;
                    (UIControlContainer.Content as UserControl).Width = UIControlContainer.ActualWidth;
                }
            }
        }
享受吧


<> P.S.Access,我为UWP做了。

< P>我遇到了类似的问题,花了我几个小时来找出解决方案。解决的问题是使用DokPad作为父容器而不是堆栈面板。只要功能类似于垂直StAdPosik,就指定所有的孩子要停靠在顶部。考虑使用LaSTaStHealth=“false”。在Dock XAML中,这是默认值

因此,不是:

SomeTextBox

谢谢你的回复。但是我不太理解你的回答
  UIControlContainer.Content = new UIDeviceSelection() { 
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
Height = UIControlContainer.ActualHeight,
Width = UIControlContainer.ActualWidth
};
 UIControlContainer.SizeChanged += UIControlContainer_SizeChanged;

 private void UIControlContainer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (UIControlContainer.Content != null)
            {
                if (UIControlContainer.Content is UserControl)
                {
                    (UIControlContainer.Content as UserControl).Height = UIControlContainer.ActualHeight;
                    (UIControlContainer.Content as UserControl).Width = UIControlContainer.ActualWidth;
                }
            }
        }