Wie kann ich ScrollViewer dazu bringen, in einem StackPanel zu arbeiten?

74

In der folgenden WPF XAML funktioniert der ScrollViewer nicht (er zeigt eine Bildlaufleiste an, aber Sie können nicht scrollen und der Inhalt wird aus dem Fenster nach unten verschoben).

Ich kann das äußere StackPanel in ein Grid ändern und es wird funktionieren.

In meiner Anwendung, aus der ich den folgenden Code reproduziert habe, benötige ich jedoch ein äußeres StackPanel. Was muss ich mit dem StackPanel tun, damit der ScrollViewer eine verwendbare Bildlaufleiste anzeigt? zB VerticalAlignment = "Stretch" Height = "Auto" funktioniert nicht.

 <StackPanel>
        <ScrollViewer>
            <StackPanel>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
                <TextBlock Text="This is a test"/>
            </StackPanel>
        </ScrollViewer>
 </StackPanel>
Edward Tanguay
quelle

Antworten:

58

Sie können nicht ohne die Höhe der StackPanel. Es ist so konzipiert, dass es unbegrenzt in eine Richtung wächst. Ich würde empfehlen, eine andere zu verwenden Panel. Warum "brauchen" Sie ein Äußeres StackPanel?

Kent Boogaart
quelle
13
wollte Dinge stapeln und mit dem Grid müssen Sie alle Zeilen und Spalten manuell verwalten, aber DockPanel funktioniert gut, also werde ich darauf umsteigen, danke.
Edward Tanguay
1
Ich stimme Edward zu. Nach meiner Erfahrung hat es hervorragend funktioniert, meine DataGrids in ein DockPanel zu packen und dann DockPanel.Dock = "Top" für jedes DataGrid festzulegen.
BitsAndBytes
2
Welche alternative Steuerung sollte ich in UWP verwenden? Es gibt kein DockPanel. Vielen Dank.
Jan Chalupa
1
Für UWP können Sie RelativePanel
xmashallax
2
Verdammtes Stackpanel, ich muss es immer durch ein Gitter auf UWP ersetzen, sie sollten sein Verhalten ändern, es ist das einzige Panel, das so funktioniert
Alberto Rivelli
57

Das hat mich auch eine Weile nervt. Der Trick besteht darin, das Stackpanel in einen Scrollviewer zu stellen.

Außerdem müssen Sie sicherstellen, dass Sie die CanContentScroll-Eigenschaft des Bildlauf-Viewers auf True setzen. Hier ein Beispiel:

  <ScrollViewer Grid.Row="1" Margin="299,12,34,54" Name="ScrollViewer1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Height="195" CanContentScroll="True">
        <StackPanel Name="StackPanel1" OverridesDefaultStyle="False"  Height="193" Width="376" VerticalAlignment="Top" HorizontalAlignment="Left"></StackPanel>
  </ScrollViewer>
rauben
quelle
Wo befindet sich die CanContentScroll-Eigenschaft? Siehe msdn.microsoft.com/en-us/library/…
Gideon
2
Schwindlig> Bitte sehen Sie diesen Link: - msdn.microsoft.com/en-us/library/ms612683.aspx
Kushal Waikar
1
"Sie müssen sicherstellen, dass Sie die CanContentScroll-Eigenschaft des Bildlauf-Viewers auf True setzen" --- Ich kann immer noch nicht glauben, dass dies nicht die Standardeinstellung für ein Steuerelement mit dem Namen "ScrollViewer" ist.
Andrea Antonangeli
@AndreaAntonangeli Ich glaube nicht, dass ' CanContentScroll ' bedeutet, was Sie denken, dass es bedeutet. Wenn "echtes" Scrollen pro Element (oder Inhalt) durchgeführt wird, wenn "falsches" Scrollen immer noch auftritt, jedoch auf
Pixelebene
8

Beachten Sie, dass Sie manchmal ein StackPanel haben, ohne es zu merken. In meinem Fall hatte ich diesen Code

<ScrollViewer>
  <ItemsControl ItemsSource="{Binding Pages}"/>
</ScrollViewer>

das hat gut funktioniert. Die "Seiten", auf die durch die Bindung verwiesen wird, waren wirklich andere, komplexe UserControls, und ich wollte nur Bildlaufleisten auf einigen von ihnen haben. Also habe ich den Scrollviewer entfernt:

 <ItemsControl ItemsSource="{Binding Pages}"/>

Und dann habe ich den ScrollViewer als oberstes Element in die Benutzersteuerelemente eingefügt, in denen ich sie haben wollte. Dies funktionierte jedoch nicht. Der Inhalt ist gerade von der Seite geflossen. Zuerst dachte ich nicht, dass diese Frage / Antwort mir helfen könnte, aber ich erkannte, dass das Standard-ItemPanel eines ItemsControl das StackPanel ist. Also habe ich mein Problem gelöst, indem ich ein ItemsPanel angegeben habe, das nicht das StackPanel war:

<ItemsControl ItemsSource="{Binding Pages}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
TJKjaer
quelle
5

So funktioniert es:

<Window x:Class="TabControl.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
    xmlns:local="clr-namespace:TabControl"
    Title="MainWindow"    Height="300"   
    DataContext="{Binding RelativeSource={RelativeSource Self}}"         
    >    
<StackPanel>
    <ScrollViewer Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Border}},Path=ActualHeight}" >
        <StackPanel >
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
            <TextBlock Text="This is a test"/>                <TextBlock Text="This is a test"/>
        </StackPanel>
    </ScrollViewer>
</StackPanel>

Durch Binden der Höhe des ScrollViewer an die innere Höhe des Fensters.

Die Logik der Größenänderung besteht darin, dass wir jedem Element eine feste Höhe geben oder die Ansicht so gestalten müssen, dass die Renderhöhe verwendet wird.

Ausgabe:

Bildlaufleiste im Stackpanel

Kylo Ren
quelle
Es ist ein bisschen nah, aber nicht ganz. Einige Steuerelemente, die Vorläufer des ScrollViewer sind, sich jedoch zwischen Border und dem ScrollViewer befinden, haben möglicherweise einen Rand (meiner), und die Bindung an den ActualHeight-Wert wird dies nicht erfassen.
Alan McBee - MSFT
@AlanMcBee Ja, es kann viele mögliche Fälle geben, in denen es nicht perfekt funktioniert, aber dies ist der grundlegendste Fall für eine Steuerungshierarchie, die ich der Lösung gegeben habe. Wenn Sie jedoch die Logik berücksichtigen, müssen Sie in den meisten Fällen den Ahnen-Typ in Ihrer Bindung ändern, und es sollte wieder einwandfrei funktionieren. Der Kern des Fixes war, dass es ein UI-Element in der Hierarchie gab, das uns helfen konnte, von einer Höhe (nicht unbedingt einem Rand) abhängig zu sein. Die Logik kann dieselbe bleiben, solange Sie eine zuverlässige Höhe finden. Hoffe es macht Sinn, sonst poste dein Problem als Frage, ich werde versuchen zu helfen. :)
Kylo Ren
x:Typenicht gefunden.
Großaugen
@Bigeyes Welche .net-Version und VS-Version verwenden Sie?
Kylo Ren
@KyloRen. Visual Studio 2010 und .Net 4.0.
Großaugen
4

Die Art und Weise, wie ich diesen Dileman gelöst habe, bestand darin, das äußere Stapelfeld zu entfernen und stattdessen den Scrollviewer an die gewünschte Position innerhalb des Hauptgitters zu bringen.

        <Grid Style="{StaticResource LayoutRootStyle}">
    <Grid.RowDefinitions>
        <RowDefinition Height="160"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>        

    <!-- Vertical scrolling grid used in most view states -->    

        <ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto">
            <StackPanel Orientation="Horizontal">
                <GridView>
                ...
                </GridView>
            </StackPanel>
        </ScrollViewer>        
Luis Delgado
quelle
2

So würde ich es machen, wenn sich Ihr Stack-Panel in einem Raster befindet:

<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
    <StackPanel MaxHeight="{Binding Path=Height,RelativeSource={RelativeSource 
              AncestorType=Grid}}">
    </StackPanel>
</ScrollViewer>
Dominic Picard
quelle
1

Das Verschieben von Grid.Row = "1" von StackPanel nach ScrollViewer hat es für mich vollständig gelöst.

Ich hatte eine lange Liste von 40 Elementen in einem StackPanel, aber nur die ersten 20 wurden angezeigt.

    <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
        <StackPanel x:Name="ContentPanel" Margin="12,0,12,0">
        <TextBlock Text="{Binding Line1}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        <TextBlock Text="" Margin="10,-2,10,0" Style="{StaticResource PhoneTextNormalStyle}" />
        ...
        </StackPanel>
    </ScrollViewer>
user3522840
quelle