Jak zmusić dzieci StackPanel do wypełnienia maksymalnej przestrzeni w dół?

356

Chcę po prostu tekst ciągły po lewej stronie i pole pomocy po prawej stronie.

Pole pomocy powinno sięgać do samego dołu.

Jeśli wyjmiesz zewnętrzną część StackPanelponiżej, działa to świetnie.

Ale ze względu na układ (dynamicznie wstawiam UserControls) muszę mieć opakowanie StackPanel.

Jak mogę GroupBoxrozciągnąć do dołu StackPanel, jak widać, próbowałem:

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

Odpowiedź:

Dzięki Mark, używając DockPanelzamiast StackPanelwyczyścić to. Ogólnie rzecz biorąc, DockPanelcoraz częściej używam teraz do układania WPF, oto naprawiony 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>
Edward Tanguay
źródło
Naprawiono formatowanie - nie lubi przechodzenia prosto z listy do kodu
Greg
1
Czy potrafisz samodzielnie rozciągnąć GroupBox? Jeśli tak, zacznij dodawać elementy nadrzędne jeden po drugim, aż dowiesz się, który z nich łamie układ.
Drew Noakes,
RoBorg: miło wiedzieć, że wprawiło mnie to w zakłopotanie, dzięki
Edward Tanguay
1
Dzięki. Korzystając z Twojej odpowiedzi, mogłem użyć 2 zagnieżdżonych paneli dokujących, aby rozwiązać mój bardzo podobny problem!
Yablargo

Odpowiedzi:

344

Wygląda na to, że chcesz, aby StackPanelostatni element zużył całą pozostałą przestrzeń. Ale dlaczego nie użyć DockPanel? Udekoruj pozostałe elementy za DockPanelpomocą DockPanel.Dock="Top", a następnie twoja kontrola pomocy może wypełnić pozostałe miejsce.

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>

Jeśli korzystasz z platformy, która nie jest DockPaneldostępna (np. WindowsStore), możesz stworzyć ten sam efekt za pomocą siatki. Oto powyższy przykład zrealizowany za pomocą siatek:

<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>
Mark Heath
źródło
18
Znakomity! Spędziłem ostatnią godzinę próbując dowiedzieć się, jak zmusić StackPanel do tego. Od tej pory poszukaj tutaj moich informacji WPF (i innych).
paxdiablo
7
Nie mogę uwierzyć, ile czasu spędziłem, próbując zmusić StackPanels do zrobienia tego, co chciałem. Dzięki za udostępnienie! DockPanels są tym, czego od zawsze chciałem.
danglund
Wygląda na to, że nie ma panelu dokującego dla tabletów. telerik.com/forums/following-blog-post-and-comparison
JP Hellemons
1
Brak panelu dokowania dla aplikacji ze Sklepu Windows.
Teoman shipahi
Teraz chodzi o uniwersalną aplikację, a uniwersalne aplikacje nie obsługują jeszcze DockPanel?
yonexbat
105

Dzieje się tak dlatego, że panel stosu mierzy każdy element potomny z dodatnią nieskończonością jako ograniczenie dla osi, na której układa elementy. Kontrolki potomne muszą zwracać, jak duże chcą być (dodatnia nieskończoność nie jest prawidłowym powrotem z MeasureOverride w obu osiach), więc zwracają najmniejszy rozmiar, w którym wszystko się zmieści. Nie mają możliwości dowiedzenia się, ile miejsca naprawdę muszą wypełnić.

Jeśli twój widok nie musi mieć funkcji przewijania, a powyższa odpowiedź nie odpowiada Twoim potrzebom, sugeruję wdrożenie własnego panelu. Prawdopodobnie możesz wywodzić bezpośrednio ze StackPanel, a następnie wszystko, co musisz zrobić, to zmienić metodę ArrangeOverride , tak aby dzieliła pozostałe miejsce między elementy potomne (dając im taką samą ilość dodatkowego miejsca). Elementy powinny dobrze renderować, jeśli mają więcej miejsca, niż chcą, ale jeśli dasz im mniej, zaczniesz zauważać usterki.

Jeśli chcesz móc przewijać całość, obawiam się, że będzie to nieco trudniejsze, ponieważ ScrollViewer daje ci nieskończoną ilość miejsca do pracy, dzięki czemu będziesz w tej samej pozycji, w jakiej były elementy potomne pierwotnie. W tej sytuacji możesz chcieć utworzyć nową właściwość w nowym panelu, która pozwala określić rozmiar rzutni, powinieneś być w stanie powiązać to z rozmiarem ScrollViewera. Idealnie byłoby zaimplementować IScrollInfo , ale zaczyna się komplikować, jeśli zamierzasz zaimplementować wszystko poprawnie.

Caleb Vear
źródło
+1, dałbym więcej, ale tylko 1 jest dozwolony, w pierwszym akapicie wskazano, czego nie udało się wielu stronom Microsoft, a mianowicie, dlaczego nieskończoność może występować jako wysokość / szerokość i fakt, że nie można polegać na zwróceniu wartości dostępnej Rozmiar z MeasureOverride .
Aidan
StackPanel wewnątrz siatki z łatwością zaspokaja jego dość powszechną potrzebę. W razie potrzeby dolny bit można umieścić w ScrollViewer. Robię WPF od 2006 roku i tylko raz potrzebowałem zrobić niestandardowy panel. Nie sądzę, że dobrym pomysłem jest zachęcanie do większej złożoności.
Chris Bordeman
@ChrisBordeman Nie jestem pewien, czy rozumiem, w jaki sposób panel stosu wewnątrz siatki rozwiązuje problem. Chodzi o to, aby mieć jeden lub więcej elementów potomnych w panelu stosu, aby wypełnić dostępną przestrzeń. Umieszczenie panelu stosu w siatce nie oznacza, że ​​to robi?
Caleb Vear
61

Alternatywną metodą jest użycie siatki z jednej kolumny, a n rzędów. Ustaw wszystkie wysokości wierszy na Auto, a najniższą wysokość wiersza na 1*.

Wolę tę metodę, ponieważ odkryłem, że siatki mają lepszą wydajność układu niż DockPanels, StackPanels i WrapPanels. Ale chyba, że ​​używasz ich w ItemTemplate (gdzie układ jest wykonywany dla dużej liczby elementów), prawdopodobnie nigdy tego nie zauważysz.

rcabr
źródło
1
dla mnie najlepsze rozwiązanie. dzięki temu można zdefiniować więcej niż jeden rosnący rząd
niyou
18

Możesz użyć SpicyTaco.AutoGrid - zmodyfikowanej wersji 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>

Pierwszy przycisk będzie wypełniony.

Możesz zainstalować go za pomocą NuGet:

Install-Package SpicyTaco.AutoGrid

Polecam rzucić okiem na SpicyTaco.AutoGrid . Jest to bardzo przydatne w przypadku formularzy w WPF zamiast DockPanel, StackPanela Gridi rozwiązywać problemy z rozciąganiem bardzo łatwo i bezpiecznie. Wystarczy spojrzeć na plik readme na GitHub.

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

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

    <Label Content="Comment:"/>
    <TextBox/>
</st:AutoGrid>
Dvor_nik
źródło