Почему ScrollViewer не ограничивает вертикальное расширение? - PullRequest
0 голосов
/ 20 апреля 2019

Я работаю с 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 Ответ

1 голос
/ 20 апреля 2019

Всего лишь совет ... вам будет немного лучше получать ответы в будущем, предоставив правильный MCVE . В этом конкретном случае ваша проблема может быть сведена к следующему:

<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>

Когда вы делаете Height="Auto" в своем определении строки, вы в основном говорите: «выделите элементам управления в этой строке столько места, сколько им нужно, что ScrollViewer незамедлительно делает независимо от того, сколько места имеет его родительский элемент. Когда вы используете Авто в в сочетании с более чем одной строкой вы фактически сообщаете менеджеру макета, что ожидаете, что первая строка никогда не превысит объем доступного пространства ... в противном случае, зачем вам объявлять другую строку под ним?

Причина, по которой макет WPF сложен, заключается в том, что он отличается от большинства других макетов. Большинство вещей начинаются сверху и идут вниз, выясняя, сколько места можно выделить, исходя из того, сколько доступно. WPF начинает с того, что спрашивает у каждого элемента управления, сколько ему нужно, а затем работает. Как только он достигает вершины, он спускается вниз, назначая реальные размеры. Так что в вашем случае у вас есть этот ScrollViewer, запрашивающий больше места, чем на самом деле доступно, но он находится внутри примерно 7 или 8 слоев вложенных панелей сетки. На каждом уровне, проходя вверх по дереву, менеджер компоновки смотрит на эти слова «как мне разделить доступное пространство между дочерними элементами этой таблицы?», И каждый из них задает «Авто» для рассматриваемой строки, что эффективно говоря "дайте этой конкретной строке столько, сколько она хочет, даже если это больше, чем я могу предложить".

Я знаю, что это, вероятно, не то, что вы хотите услышать, но я бы предложил выбросить весь макет и начать заново. RowSpan и ColumnSpan являются абсолютно ключевыми в макетах, подобных этому, если вы начнете использовать их, то обнаружите, что можете свернуть все это до нескольких вложенных слоев, и у вас не будет проблем со ScrollViewer, подобных описанной выше. Если это не вариант, вам придется самостоятельно переходить по визуальному дереву, меняя каждое RowDefinition с Auto на что-то еще, что лучше соответствует вашим фактическим требованиям GUI.

...