Scrollviewer 在 wpf 中超出父 window 时不显示数据

Scrollviewer doesnt show data when its beyond parent window in wpf

在一个带有 6 个扩展器的网格中有大约 6 个内容控件(每个内容控件在一个扩展器中) 在我的 mainwindow 上,它调用各种用户控件来为每个上层 tab/left 菜单选择填充 mainwindow。

一次将激活一个扩展器,其余的将折叠起来。

每个新的 window 都会在一个内容控件上。

问题是当我有更大的动态加载数据时,我的内容超出了父控件,并且 即使我使用 scrollviewer 时,scrollviewer 也会出现,但数据会被切断。

这是我的代码: 以下是我在 mainwindow

的 contentcontrol 中使用的 UserControl 中的代码
<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>
  <Expander Header="Settings" BorderBrush="SteelBlue" BorderThickness="5"
      IsExpanded="{Binding Path=ShowPreview, Mode=TwoWay}"
      Background="AliceBlue" FontFamily="Poor Richard" FontSize="24"
      FontWeight="Bold">
    <DatePicker Name="MyDateRange" />
  </Expander>
  <Expander Header="Permissions" Grid.Row="1" BorderBrush="SteelBlue"
      BorderThickness="5" Background="AliceBlue" FontFamily="Poor Richard"
              <local:Permissions /> 
        <!--/*Permissions is another usercontrol   with a grid layout  (a dataentry form)*/-->
   </Expander>
</Grid>

6 行的第二个网格是我主窗口中的代码。

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Expander Grid.Row="1" IsExpanded="False" x:Name="Expander1"
      Style="{DynamicResource OutlookStyleExpanderStyle}" Visibility="Hidden">
    <Expander.Header>
      <WrapPanel HorizontalAlignment="Right" Margin="450,0,0,0">
        <Button Name="ExpandButtonMin" Background="#FFACD0EE"
            Click="ExpandButtonMin_Click" HorizontalAlignment="Right">
          <Image Source="/Images/Minimize_Box_Blue.png" Height="30" Width="30" />
        </Button>
        <Button Name="ExpandButtonMax" Background="#FFACD0EE"
            Click="ExpandButtonMax_Click" HorizontalAlignment="Right">
          <Image Source="/Images/maximize.png" Height="30" Width="30" />
        </Button>
        <Button Name="ExpandButtonClose" Background="#FFACD0EE"
            Click="ExpandButton1_Click" HorizontalAlignment="Right">
          <Image Source="/Images/Close_Box_Red.png" Height="30" Width="30" />
        </Button>
      </WrapPanel>
    </Expander.Header>
   <ScrollViewer MaxHeight="800">
    <ContentControl Grid.Row="1" x:Name="contentControl1"
        Content="{Binding ContentControlOne}" Margin="0,0,0,0"
        ScrollViewer.VerticalScrollBarVisibility="Auto" />
   </ScrollViewer>
  </Expander>
</Grid>

类似地,有 5 个带有 contentcontrol2 的扩展器行,..在每个行中。

问题是当我的内容控件具有超过父级大小的最大动态内容时,数据被切断并且显示滚动查看器但仍未显示完整数据。当我删除 scrollviewer 高度并将 scrollviewer 高度保持为 "Auto" 时,scrollviewer 根本不显示。

这里的问题是,通过将 Grid 的所有行的高度设置为 "Auto",您最终会得到 StackPanel。因此,没有单元格被强制设置为比它需要的高度更小的高度,因此 ScrollViewer 是无用的。

展开的扩展器行的高度必须为“*”。将其视为 "Each expander takes the height it needs, except the active one who takes all the remaining".

也许是这样的:

<Grid>
  <Expander x:Name="Expander1" ... />
  <Expander x:Name="Expander2" ... />
  <Expander x:Name="Expander3" ... />
  ...
  <Grid.RowDefinitions>
    <RowDefinition Height="{Binding IsExpanded, ElementName=Expander1, Converter={x:Static BoolToRowHeightConverter.Instance}}"/>
    <RowDefinition Height="{Binding IsExpanded, ElementName=Expander2, Converter={x:Static BoolToRowHeightConverter.Instance}}"/>
    <RowDefinition Height="{Binding IsExpanded, ElementName=Expander3, Converter={x:Static BoolToRowHeightConverter.Instance}}"/>
    ...
  </Grid.RowDefinitions>
</Grid>

BoolToRowHeightConverter returns GridLength.Star 如果为真,否则 GridLength.Auto.

你的问题是你如何定义网格的 RowDefinition。

Auto 表示 "allow children to grow to any size they want",因此您的 ScrollViewer 会增长到 800px 高(因为 MaxHeight),它超出了屏幕。

这种事情的标准解决方案是在 RowHeight 中使用转换器将其设置为 Auto"*" ("allow child to take up all remaining space") 基于Expander.IsExpanded 状态。

这意味着如果 Expander 折叠,它会占用任何 space 它需要的东西,但如果它展开,它将占用所有剩余的 space(仅此而已)。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander1, Converter={x:Static MyBoolToGridSizeConverter}}" />
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander2, Converter={x:Static MyBoolToGridSizeConverter}}" />
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander3, Converter={x:Static MyBoolToGridSizeConverter}}" />
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander4, Converter={x:Static MyBoolToGridSizeConverter}}" />
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander5, Converter={x:Static MyBoolToGridSizeConverter}}" />
        <RowDefinition Height="{Binding IsExpanded, ElementName=Expander6, Converter={x:Static MyBoolToGridSizeConverter}}" />
    </Grid.RowDefinitions>

    <Expander Grid.Row="0" x:Name="Expander1">
        <ScrollViewer>
            <ContentControl x:Name="contentControl1" Content="{Binding ContentControlOne}" />
        </ScrollViewer>
    </Expander>
     ...
</Grid>

如果扩展了多个项目,它们应该平均分配剩余的 space,因为它们共享 "1*" 的大小,因此会分配等量的 space .

创建转换器很简单。创建一个继承自IValueConverter的class,实现接口,修改Convert方法,将bool值(IsExpanded)转换为GridLength值行高。

public class BoolToGridSizeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        if (value is bool && (bool)value)
            return new GridLength(1, GridUnitType.Star);

        return GridLength.Auto;
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        // this is not needed
    }
}

然后将此转换器的一个实例添加到您的 XAML 某处的资源中,例如

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

当然,另一种选择是google一个免费的WPF手风琴控件,例如WPF Toolkit :)