2012-07-05 12 views
13

Ich muss Elemente (alle von gleicher Größe) vertikal (mit einem ScrollViewer) auflisten. Ich möchte, dass die Elemente, die über x Spalten verteilen, wenn der Behälter groß genug ist, x SpaltenElemente vertikal auf einem WrapPanel auflisten und mehrere Spalten nutzen

ich zum ersten Mal versucht, anzuzeigen, dass:

<ScrollViewer> 
    <toolkit:WrapPanel Orientation="Horizontal" ItemHeight="30" ItemWidth="100"> 
     <Button Content="1" /> 
     <Button Content="2" /> 
     <Button Content="3" /> 
     <Button Content="4" /> 
     <Button Content="5" /> 
    </toolkit:WrapPanel> 
</ScrollViewer> 

Ergebnis - Die WrapPanel funktioniert wie ich will, aber meine Artikel sind von "von links nach rechts" bestellt (nicht vertikal

Dann habe ich versucht, die Orientierung des WrapPanel auf „Vertical“ seet:

Ergebnis - Meine Artikel bestellt vertikal, aber nicht auf mehrere Spalten gespreizt.

Hier ist, wie ich Artikel möchte gerendert werden:

ich wirklich Code zu schreiben, um zu vermeiden mag, dass die Steuergröße Überwachung Spalten erstellen/entfernen von seiner Größe abhängig.

Antwort

9

Wenn Sie Orientation auf Vertical setzen, sollten Sie auch die Renderhöhe einstellen. Zum Beispiel zu WrapPanel, Height="150".

+0

ich die Höhe des WrapPanel sein will dynamisch den vertikalen Abstand zu nehmen braucht es Artikel in 2 Spalten angezeigt werden (oder 3, oder 4, etc .. abhängig von der Breite des Steuerelements) – danbord

+0

@danbord, es funktioniert nicht so. Das 'WrapPanel' platziert alle Elemente, die in die erste Spalte passen, vertikal und alle verbleibenden Elemente werden in der nächsten Spalte angezeigt. In diesem Fall platziert das 'WrapPanel' alle Objekte in einer Spalte, da die Höhe begrenzt ist. – Zabavsky

1

Die einzige Möglichkeit, dies mit einem WrapPanel zu tun, ist die Height explizit festzulegen.

Es sieht so aus, als ob die Objekte gleichmäßig über die Spalten verteilt werden sollen, wobei die linke Spalte höchstens ein Element mehr als die Spalte rechts hat. Wenn Sie danach suchen, müssen Sie ein eigenes benutzerdefiniertes Panel erstellen. Werfen Sie einen Blick auf this, um zu sehen, wie Sie beginnen. Sie benötigen eine ItemWidth- und ItemHeight-Abhängigkeitseigenschaften und berechnen anhand der ItemWidth und der verfügbaren Breite, wie viele Spalten Sie haben können.

2

Diese Art von Verhalten nicht möglich ist, mit einem WrapPanel ohne seine Definition von Height

Eine Alternative Sie ein Grid verwenden könnte, ist, wo in OnLoaded und OnSizeChanged berechnet er, wie viele Spalten passen, dann die Reihe Sätze/Spaltendefinitionen des Gitters und die Grid.Row/Grid.Column jedes Objekts im Code-behind. Es ist nicht schön, aber es sollte ziemlich einfach zusammenzustellen sein und wird funktionieren.

Die andere Möglichkeit wäre, ein eigenes benutzerdefiniertes Panel zu erstellen, das die Elemente so anordnet, wie Sie möchten. Sie könnten sogar in der Lage sein, etwas online verfügbar zu finden, das tut das schon

3

Schließlich bekam etwas, das funktioniert, aber es braucht Code. Ich stimme Ihnen allen zu, wenn Sie sagen, dass wir die Höhe des WrapPanels anpassen müssen, damit das funktioniert.Hier ist meine Lösung:

<ScrollViewer x:Name="scroll1" SizeChanged="ScrollViewer_SizeChanged" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
    <toolkit:WrapPanel x:Name="wp1" Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Left" ItemHeight="30" ItemWidth="250" > 
     <Button Content="1" /> 
     <Button Content="2" /> 
     <Button Content="3" /> 
     <Button Content="4" /> 
     <Button Content="5" /> 
     <Button Content="6" /> 
     <Button Content="7" /> 
     <Button Content="8" /> 
    </toolkit:WrapPanel> 
</ScrollViewer> 

Hier wird der Codebehind:

private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    // Stupid magical number because ViewPortHeight is sometimes not accurate 
    Double MAGICALNUMBER = 2; 

    // Ensure ViewPortSize is not 0 
    if (scroll1.ViewportWidth <= MAGICALNUMBER || scroll1.ViewportHeight <= MAGICALNUMBER) 
     return; 

    Size contentSize = new Size(scroll1.ViewportWidth - MAGICALNUMBER, scroll1.ViewportHeight - MAGICALNUMBER); 
    Size itemSize = new Size(wp1.ItemWidth, wp1.ItemHeight); 

    Size newSize = CalculateSizeBasedOnContent(contentSize, wp1.Children.Count, itemSize); 

    wp1.Width = newSize.Width; 
    wp1.Height = newSize.Height; 
} 


private Size CalculateSizeBasedOnContent(Size containerSize, int itemsCount, Size itemSize) 
{ 

    int iPossibleColumns = (int)Math.Floor(containerSize.Width/itemSize.Width); 
    int iPossibleRows = (int)Math.Floor(containerSize.Height/itemSize.Height); 

    // If all items can fit in first column without scrolling (or if container is narrow than the itemWidth) 
    if (itemsCount <= iPossibleRows || containerSize.Width < itemSize.Width) 
    return new Size(itemSize.Width, (itemsCount * itemSize.Height)); 

    // If all items can fit in columns without scrollbar 
    if (iPossibleColumns * iPossibleRows > itemsCount) 
    { 
    int columnsNeededForDisplay = (int)Math.Ceiling((itemsCount/(Double) iPossibleRows)); 
    return new Size(columnsNeededForDisplay * itemSize.Width, containerSize.Height); 
    } 

    // Here scrolling is needed even after spreading in columns 
    int itemsPerColumn = (int)Math.Ceiling(wp1.Children.Count/(Double)iPossibleColumns); 
    return new Size(containerSize.Width, itemsPerColumn * itemSize.Height); 

} 
+0

Ich habe gerade vor kurzem mit 'ScrollViewer.ViewportHeight' herumgespielt ... vielleicht könnte der untere Teil von [diese Antwort] (http://stackoverflow.com/a/11157916/302677) Ihnen helfen? – Rachel

+0

+1: Dies funktionierte gut für mich mit einigen sehr kleinen Verbesserungen. Danke für die Lösung! :) – reSPAWNed

+2

Nur ein Hinweis: Wenn Sie ein ItemsControl anstelle von einem WrapPanel verwenden und Sie die ItemsSource dynamisch ändern, wird es nicht folgen, bis Sie die Größe des Fensters ändern. Ich habe es funktioniert, indem Sie das LayoutUpdated-Ereignis anstelle des SizeChanged-Ereignisses verwenden, das öfter aufgerufen wird, aber wie Sie lesen können, wird MSDN bevorzugt, wenn Sie mit dem Layout herumspielen. – reSPAWNed