ScrollViewer为什么不限制垂直扩展?

时间:2019-04-19 21:12:39

标签: wpf scrollviewer

我已经使用WPF几年了,但是布局机制常常使我感觉像个菜鸟(也许我仍然是)。我的页面相当复杂。在下面,我消除了许多无关的内容,但保留了页面的一般结构。我有两个ItemsControls。两者都有ScrollViewers。它们都曾经用ScrollViewrs包装<ItemsPresenter />。我看到的一篇帖子让我尝试移动第一个帖子来包装整个ItemsControl,以查看是否解决了我的问题。没有。

ItemsControls之间的主要区别在于,第一个对内容具有一系列DataTemplates,第二个对内联内容进行定义。

一切正常显示,除了第一个强制其Grid单元格扩展以容纳所有内容,而不是启用垂直滚动条。第二个实例在内容太长时正确激活了ScrollViewer

我想念什么? (希望我刚刚错过了一些愚蠢的事情。)

这是我的XAML:

<vsupport:CBUserControlBase x:Class="CB.WPFClient.Views.BillingMasterView" ... >
  <vsupport:CBUserControlBase.Resources>
    <Storyboard>
      <ThicknessAnimation />
    </Storyboard>

    <Storyboard>
      <ThicknessAnimation />
    </Storyboard>
  </vsupport:CBUserControlBase.Resources>

  <Grid Margin="1" IsEnabled="{Binding Path=IsBusy, Converter={StaticResource BoolInverse}}">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <local:FirmSelectorView Grid.Row="0" Margin="1,1,1,1"/>

    <Grid Grid.Row="1" ClipToBounds="False">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="3*" />
      </Grid.ColumnDefinitions>

      <Grid Grid.Column="0" Margin="1,0,0,0">
        <!-- Unrelated Content -->
      </Grid>

      <Grid Grid.Column="1" Margin="1,0,0,0">
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="*" />
          <RowDefinition Height="*" />
          <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Grid.IsSharedSizeScope="True">
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>

          <Grid Grid.Row="0" Background="White">
            <!-- Unrelated Content -->
          </Grid>

          <Grid Grid.Row="1" Margin="0,1,0,0">
            <!-- Unrelated Content -->
          </Grid>

          <Grid Grid.Row="2" Margin="0,1,0,0">
            <!-- Unrelated Content -->
          </Grid>

          <Grid Grid.Row="3" Margin="0,1,0,0">
            <!-- Unrelated Content -->
          </Grid>

          <!-- Notes and Related Entities -->
          <Grid Grid.Row="4" Margin="0,1,0,0">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="*" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Grid Grid.Column="0">
              <!-- Unrelated Content -->
            </Grid>

            <!-- Related Entities -->
            <Grid Grid.Column="1" Margin="1,0,0,0">
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
              </Grid.RowDefinitions>

              <Label Grid.Column="0" Background="{StaticResource brush_Logo}" Foreground="White" Padding="5,0,0,0" Height="24"
                HorizontalContentAlignment="Left" VerticalContentAlignment="Center"
                Content="Related Entities" />

              <!-- This one expands when multiple content items are longer than vertical space. -->
              <!-- Scroll viewer used to be inside ItemsControl. Tried moving it to see if that helped. -->
              <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Hidden">
                <ItemsControl  ItemsSource="{Binding Path=RelatedEntities}" x:Name="RelatedEntitiesItemsControl">
                  <ItemsControl.Resources>

                    <DataTemplate DataType="{x:Type models:C}">
                      <Grid Margin="2,2,2,2">
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="Auto" />
                          <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0" CornerRadius="5,0,0,5" Padding="0,2,0,2">
                          <TextBlock Foreground="White" FontSize="10" Background="Transparent">
                          </TextBlock>
                        </Border>

                        <Border Grid.Column="1" Background="#FFF5F7FF" CornerRadius="0,5,5,0" Margin="3,0,0,0">
                          <Grid>
                          </Grid>
                        </Border>
                      </Grid>
                    </DataTemplate>

                    <DataTemplate DataType="{x:Type models:P}">
                      <Grid Margin="2,2,2,2">
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="Auto" />
                          <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0" CornerRadius="5,0,0,5" Padding="0,2,0,2" Background="{StaticResource brush_Plan}">
                          <TextBlock Foreground="White" FontSize="10" Background="Transparent">
                          </TextBlock>
                        </Border>

                        <Border Grid.Column="1" Background="#FFF5F7FF" CornerRadius="0,5,5,0" Margin="3,0,0,0">
                          <Grid>
                          </Grid>
                        </Border>
                      </Grid>
                    </DataTemplate>

                    <DataTemplate DataType="{x:Type models:A}">
                      <Grid Margin="2,2,2,2">
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="Auto" />
                          <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0" CornerRadius="5,0,0,5" Padding="0,2,0,2" Background="{StaticResource brush_Account}">
                          <TextBlock Foreground="White" FontSize="10" Background="Transparent">
                          </TextBlock>
                        </Border>

                        <Border Grid.Column="1" Background="#FFF5F7FF" CornerRadius="0,5,5,0" Margin="3,0,0,0">
                          <Grid>
                          </Grid>
                        </Border>
                      </Grid>
                    </DataTemplate>
                  </ItemsControl.Resources>

                  <ItemsControl.Template>
                    <ControlTemplate TargetType="{x:Type ItemsControl}">
                    <!-- Old ScrollViewer Location -->
                      <ItemsPresenter />
                    <!-- Old ScrollViewer Location -->
                    </ControlTemplate>
                  </ItemsControl.Template>
                </ItemsControl>
              </ScrollViewer>
            </Grid>
          </Grid>
        </Grid>

        <ContentControl Grid.Row="1">
        </ContentControl>

        <Grid Grid.Row="2" Margin="0,1,0,0">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>

          <Grid Grid.Column="0">
          </Grid>

          <Grid Grid.Column="1" Margin="1,0,0,0">
          </Grid>

          <!-- This one works properly -->
          <Grid Grid.Column="2" Margin="1,0,0,0">
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <Grid Grid.Row="0">
            </Grid>

            <ItemsControl Grid.Row="1" AlternationCount="2" ItemsSource="{Binding Path=Stuff}">
              <ItemsControl.Template>
                <ControlTemplate TargetType="{x:Type ItemsControl}">
                  <ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto">
                    <ItemsPresenter />
                  </ScrollViewer>
                </ControlTemplate>
              </ItemsControl.Template>

              <ItemsControl.ItemTemplate>
                <DataTemplate>
                  <Grid Margin="0,1,0,0">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="30" />
                      <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Label  />

                    <Label  />
                  </Grid>

                  <DataTemplate.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                      <Setter Property="Background" Value="WhiteSmoke" TargetName="StaticTextLabel" />
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                      <Setter Property="Background" Value="{StaticResource brush_LogoLight}" TargetName="StaticTextLabel" />
                    </Trigger>
                  </DataTemplate.Triggers>
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </Grid>
        </Grid>

        <Grid Grid.Row="3" Margin="0,1,0,0">
        </Grid>
      </Grid>
    </Grid>
  </Grid>
</vsupport:CBUserControlBase>

1 个答案:

答案 0 :(得分:1)

只是一个提示。...通过提供适当的MCVE,您将来会有更好的运气来获得答案。在这种情况下,您的问题可以归结为:

queue

当您在行定义中执行<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Hidden"> <ItemsControl> <ItemsControl.ItemsSource> <x:Array Type="{x:Type sys:String}"> <sys:String>Hello World</sys:String> <sys:String>Goodbye World</sys:String> <sys:String>Hello World</sys:String> <sys:String>Goodbye World</sys:String> <!-- ... etc ... --> <sys:String>Hello World</sys:String> <sys:String>Goodbye World</sys:String> </x:Array> </ItemsControl.ItemsSource> </ItemsControl> </ScrollViewer> </Grid> 时,您基本上是在说:“给该行上的控件提供所需的空间,无论其父级有多少空间,ScrollViewer都会立即执行。自动结合多个行,可以有效地告诉布局管理器您希望第一行永远不会超过可用空间...否则,为什么还要在其下面声明另一行?

WPF布局之所以棘手是因为它与大多数其他布局不同。大多数事情都是从顶部开始,然后一直向下,然后根据可用空间来确定要分配多少空间。 WPF首先询问每个控件所需的数量,然后逐步提高。一旦到达顶部,然后返回指定实际尺寸。因此,在您的情况下,您使ScrollViewer要求的空间比实际可用空间大,但它位于大约7层或8层嵌套的Grid面板中。在走树的每一层中,布局管理器都在看这句话:“我应该如何在Grid的子元素之间分配可用空间?”,并且其中的每一个都为所涉及的行指定“自动”,这实际上是有效的说“即使没有必要,也要尽可能多地给予此特定行”。

我知道这可能不是您想听到的,但是我的建议是将整个布局扔掉,然后重新开始。在这样的布局中,RowSpan和ColumnSpan绝对是关键,如果您开始使用它们,您会发现可以将整个内容折叠到几个嵌套层中,并且不会出现像上面那样的ScrollViewer问题。如果这不是一个选择,那么您将必须自己走到可视化树上,将每个RowDefinition从Auto更改为更好地满足您的实际GUI要求的其他东西。