Как заставить дочерние элементы StackPanel заполнять максимальное пространство вниз?

Мне просто нужен плавный текст слева и окно справки справа.

Поле помощи должно доходить до самого низа.

Если вынуть внешний StackPanel ниже, он отлично работает.

Но из соображений компоновки (я вставляю UserControls динамически) мне нужна упаковка StackPanel.

Как мне сделать так, чтобы GroupBox простирался до нижней части StackPanel, как видите, я пробовал:

  • VerticalAlignment="Stretch"
  • VerticalContentAlignment="Stretch"
  • Height="Auto"

XAML:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600">
    <StackPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                Background="Beige" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" />
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </StackPanel>
</Window>

Отвечать:

Спасибо, Марк, использование DockPanel вместо StackPanel прояснило ситуацию. В общем, теперь я все чаще и чаще использую DockPanel для компоновки WPF, вот исправленный XAML:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600" MinWidth="500" MinHeight="200">
    <DockPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            MinWidth="400"
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <Border CornerRadius="3" Background="Beige">
                    <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" 

                Padding="5"/>
                </Border>
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </DockPanel>
</Window>

person Edward Tanguay    schedule 20.02.2009    source источник
comment
Исправлено форматирование - не нравится переходить прямо от списка к коду   -  person Greg    schedule 20.02.2009
comment
Можно ли растянуть GroupBox таким образом? Если это так, начните добавлять родительские элементы один за другим, пока не выясните, какой из них нарушает макет.   -  person Drew Noakes    schedule 20.02.2009
comment
Роборг: приятно знать, это меня озадачило, спасибо   -  person Edward Tanguay    schedule 20.02.2009
comment
Спасибо. Используя ваш ответ, я смог использовать 2 вложенных DockPanel для решения моей очень похожей проблемы!   -  person Yablargo    schedule 28.02.2017


Ответы (4)


Похоже, вам нужен StackPanel, где последний элемент использует все оставшееся пространство. Но почему бы не использовать DockPanel? Украсьте другие элементы в DockPanel DockPanel.Dock="Top", и тогда ваш вспомогательный элемент управления сможет заполнить оставшееся пространство.

XAML:

<DockPanel Width="200" Height="200" Background="PowderBlue">
    <TextBlock DockPanel.Dock="Top">Something</TextBlock>
    <TextBlock DockPanel.Dock="Top">Something else</TextBlock>
    <DockPanel
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        Height="Auto" 
        Margin="10">

      <GroupBox 
        DockPanel.Dock="Right" 
        Header="Help" 
        Width="100" 
        Background="Beige" 
        VerticalAlignment="Stretch" 
        VerticalContentAlignment="Stretch" 
        Height="Auto">
        <TextBlock Text="This is the help that is available on the news screen." 
                   TextWrapping="Wrap" />
     </GroupBox>

      <StackPanel DockPanel.Dock="Left" Margin="10" 
           Width="Auto" HorizontalAlignment="Stretch">
          <TextBlock Text="Here is the news that should wrap around." 
                     TextWrapping="Wrap"/>
      </StackPanel>
    </DockPanel>
</DockPanel>

Если вы работаете на платформе, где DockPanel недоступно (например, WindowsStore), вы можете создать тот же эффект с помощью сетки. Вот приведенный выше пример, выполненный с использованием вместо этого сеток:

<Grid Width="200" Height="200" Background="PowderBlue">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0">
        <TextBlock>Something</TextBlock>
        <TextBlock>Something else</TextBlock>
    </StackPanel>
    <Grid Height="Auto" Grid.Row="1" Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <GroupBox
            Width="100"
            Height="Auto"
            Grid.Column="1"
            Background="Beige"
            Header="Help">
            <TextBlock Text="This is the help that is available on the news screen." 
              TextWrapping="Wrap"/>
        </GroupBox>
        <StackPanel Width="Auto" Margin="10" DockPanel.Dock="Left">
            <TextBlock Text="Here is the news that should wrap around." 
              TextWrapping="Wrap"/>
        </StackPanel>
    </Grid>
</Grid>
person Mark Heath    schedule 20.02.2009
comment
Блестяще! Я потратил последний час, пытаясь понять, как заставить StackPanel сделать это. С этого момента я сначала буду искать здесь свою информацию о WPF (и других). - person paxdiablo; 22.06.2010
comment
Не могу поверить, сколько времени я потратил, пытаясь заставить StackPanels делать то, что я хотел. Спасибо, что поделился! DockPanels - это то, что я хотел с самого начала. - person Dan Gøran Lunde; 06.09.2012
comment
Док -панели для планшетов вроде нет. telerik.com/forums/following-blog-post-and-comparison < / а> - person JP Hellemons; 28.07.2014
comment
Нет док-панели для приложений Магазина Windows. - person Teoman shipahi; 22.12.2014
comment
Теперь все об универсальном приложении, а универсальные приложения еще не поддерживают DockPanel? - person yonexbat; 28.02.2016
comment
@yonexbat см. мой альтернативный ответ с сеткой - person Mark Heath; 29.02.2016
comment
@ Чувак видит альтернативный ответ с сеткой - person Mark Heath; 21.07.2016
comment
да, я говорил о вашем альтернативном ответе. это не работает. Проблема в GroupBox и DockPanel. - person Dude; 21.07.2016
comment
Спасибо за этот ответ! Я не мог понять, почему моя сетка данных внутри панели стека была отключена вместо того, чтобы иметь вертикальную полосу прокрутки. Использование панели Dock сделало свое дело! - person abaga129; 11.10.2018
comment
Док-панели тоже не идеальны. Если вы хотите, чтобы 3-й элемент заполнил оставшееся пространство, а остальные зафиксированы, вам придется проделать несколько странных манипуляций. - person A. Vieira; 26.11.2020

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

Если в вашем представлении не требуется функция прокрутки, а приведенный выше ответ вам не подходит, я бы предложил реализовать собственную панель. Вероятно, вы можете получить прямо из StackPanel, а затем все, что вам нужно сделать, это изменить ArrangeOverride, чтобы он разделил оставшееся пространство между дочерними элементами (давая каждому из них одинаковое количество дополнительного места). Элементы должны отображаться нормально, если им предоставляется больше места, чем они хотели, но если вы дадите им меньше, вы начнете видеть сбои.

Если вы хотите иметь возможность прокручивать все это, я боюсь, что все будет немного сложнее, потому что ScrollViewer дает вам бесконечное пространство для работы, с которым вы окажетесь в том же положении, что и дочерние элементы. изначально. В этой ситуации вы можете захотеть создать новое свойство на вашей новой панели, которое позволит вам указать размер области просмотра, вы должны иметь возможность привязать его к размеру ScrollViewer. В идеале вы должны реализовать IScrollInfo, но это начинает усложняться, если вы собираетесь все это реализовать должным образом.

person Caleb Vear    schedule 20.02.2009
comment
+1, я бы дал вам больше, но разрешен только 1, ваш первый абзац указал на то, что не удалось сделать на многочисленных страницах Microsoft, а именно, почему бесконечность может быть как высота / ширина, и тот факт, что вы не можете полагаться на возвращение availableSize из MeasureOverride . - person Aidan; 23.08.2012
comment
StackPanel внутри Grid с легкостью решает его довольно распространенную потребность. При необходимости нижний бит можно поместить внутрь ScrollViewer. Я занимаюсь WPF с 2006 года, и мне только однажды понадобилось создать настраиваемую панель. Я не думаю, что поощрять дополнительную сложность - хорошая идея. - person Chris Bordeman; 30.12.2019
comment
@ChrisBordeman Я не уверен, что понимаю, как панель стека внутри сетки решает проблему. Идея состоит в том, чтобы растянуть один или несколько дочерних элементов в панели стека, чтобы заполнить доступное пространство. Помещение панели стека внутри сетки не делает этого? - person Caleb Vear; 15.01.2020

Альтернативный метод - использовать сетку с одним столбцом и n строками. Установите высоту всех строк на Auto, а высоту самой нижней строки на 1*.

Я предпочитаю этот метод, потому что я обнаружил, что у Grids более высокая производительность компоновки, чем у DockPanels, StackPanels и WrapPanels. Но если вы не используете их в ItemTemplate (где макет выполняется для большого количества элементов), вы, вероятно, никогда не заметите.

person rcabr    schedule 20.02.2009
comment
для меня лучшее решение. с этим можно определить более одной растущей строки - person niyou; 09.05.2018

Вы можете использовать SpicyTaco.AutoGrid - модифицированную версию StackPanel:

<st:StackPanel Orientation="Horizontal" MarginBetweenChildren="10" Margin="10">
   <Button Content="Info" HorizontalAlignment="Left" st:StackPanel.Fill="Fill"/>
   <Button Content="Cancel"/>
   <Button Content="Save"/>
</st:StackPanel>

Первая кнопка будет заполнена.

Вы можете установить его через NuGet:

Install-Package SpicyTaco.AutoGrid

Я рекомендую взглянуть на SpicyTaco.AutoGrid. Это очень полезно для форм в WPF вместо DockPanel, StackPanel и Grid и решает проблему с растяжкой очень легко и изящно. Просто посмотрите readme на GitHub.

<st:AutoGrid Columns="160,*" ChildMargin="3">
    <Label Content="Name:"/>
    <TextBox/>

    <Label Content="E-Mail:"/>
    <TextBox/>

    <Label Content="Comment:"/>
    <TextBox/>
</st:AutoGrid>
person Dvor_nik    schedule 10.03.2016
comment
Это должно быть наверху, очень полезно, большое вам спасибо! - person IneedHelp; 26.11.2020
comment
Не забудьте добавить xmlns: st = schemas.spicytaco.io - person Richard; 03.03.2021