WPF ScrollViewer выталкивает элемент управления из окна

У меня есть DockPanel, который содержит некоторые элементы управления, включая ScrollViewer,

То, что я хочу, это для ScrollViewer чтобы прокрутить сетку, не сдвигая другие элементы управления с нижней части формы.

Вместо этого ScrollViewer расширяется до высоты окна, а не до верха Button, толкая Button выкл для нижней части формы. Почему это? Как мне это исправить?

<Window x:Class="Class1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Class1"
    mc:Ignorable="d"
    Title="MainWindow" Height="800" Width="600"
    WindowStartupLocation="CenterScreen">
<DockPanel LastChildFill="False">
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="File">
            <MenuItem Name="miQuit" Header="Quit" Click="miQuit_Click" />
        </MenuItem>
    </Menu>
    <ToolBarTray DockPanel.Dock="Top" IsLocked="True">
        <ToolBar>
            <Button Name="btnQuit" ToolBar.OverflowMode="Never" Click="btnQuit_Click">
                Quit
            </Button>
        </ToolBar>
    </ToolBarTray>
    <ScrollViewer VerticalScrollBarVisibility="Auto" DockPanel.Dock="Top" VerticalAlignment="Stretch">
        <Grid Name="gMainGrid" ScrollViewer.CanContentScroll="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBox Grid.Column="0" Grid.Row="0"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="1"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="2"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="3"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="4"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="5"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="6"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="7"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="8"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="9"   Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="10"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="11"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="12"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="13"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="14"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="15"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="16"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="17"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="18"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="19"  Width="100" Margin="10,10,10,10"/>
            <TextBox Grid.Column="0" Grid.Row="20"  Width="100" Margin="10,10,10,10"/>
        </Grid>
    </ScrollViewer>
    <Button Name="btnButton1" DockPanel.Dock="Bottom" Click="btnButton1_Click" >ButtonText</Button>
</DockPanel>

Мне нужна строка меню вверху экрана, кнопка внизу экрана и сетка с ScrollViewer в середине. Что я делаю неправильно?

2 ответа

Решение

Проблема в том, что ScrollViewer не знает, какую высоту он должен получить. ScrollViewer это элемент управления, который пытается получить столько размеров, сколько нужно его детям. DockPanel также дает столько же размеров, сколько ScrollViewer нужно и поэтому твоя проблема. Вы можете зафиксировать высоту ScrollViewer с пикселями (т.е. Height=100) Чтобы сделать это фиксированной высоты. Я не знаю ваш вариант использования, так что это может быть полезно, например, если вы показываете карусель изображений.

В более общем совете по компоновке я могу сказать, что вам лучше использовать сетку вместо DockPanel:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <!-- Next one is for middle part of the page -->
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <!-- your controls here -->
</Grid>

Я обнаружил, что у меня может быть динамическая высота с DockPanel если я сунул все это в сетку. Похоже, это работает, так как теперь я могу иметь динамическую высоту для ScrollViewer,

<Window x:Class="Class1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Class1"
    mc:Ignorable="d"
    Title="MainWindow" Height="800" Width="600"
    WindowStartupLocation="CenterScreen">
  <Grid>
      <Grid.ColumnDefinitions>
          <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
          <RowDefinition Height="*" />
          <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <DockPanel Grid.Column="0" Grid.Row="0" LastChildFill="False">

Тогда все как обычно, за исключением того, что я переместил свою кнопку за пределы DockPanel и во второй ряд таблицы:

        </DockPanel>
    <Button Grid.Column="0" Grid.Row="1" Name="btnButton1" DockPanel.Dock="Bottom" Click="btnButton1_Click" >ButtonText</Button>
</Grid>

Строки с Height из "Авто" будет размер, чтобы соответствовать их содержанию. Строки с Height звездочки (*) будет иметь размер, чтобы заполнить оставшееся пространство после расчета размера автомобилей. Таким образом, все оценивается правильно и красиво.

Кроме того, на данный момент я могу покончить с DockPanel целиком и полностью Menu, ToolBarTray, ScrollViewer, а также Button в их отдельных отдельных строках сетки, как предлагает Эмад в своем ответе (хотя я не уверен, для чего нужна дополнительная строка в их примере).

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

В конечном итоге я решил пойти на такой подход, поэтому я отмечу его как ответ, но я помещу все это здесь для полного объяснения, для полноты (на случай, если люди действительно захотят сохранить их DockPanel).

Другие вопросы по тегам