2012-07-05 19 views
13

Tôi cần liệt kê các mục (tất cả cùng kích thước) theo chiều dọc (với ScrollViewer). Tôi muốn các mục để lây lan qua x cột nếu container là đủ lớn để hiển thị x cộtMục danh sách Theo chiều dọc trên WrapPanel và tận dụng nhiều cột

đầu tiên tôi đã cố gắng rằng:

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

quả - Các WrapPanel hoạt động như tôi muốn nhưng các mặt hàng của tôi được đặt hàng từ "Trái sang phải" (không theo chiều dọc

Sau đó, tôi đã cố gắng để Seet Định hướng của WrapPanel để "Dọc":

quả - mục của tôi được sắp xếp theo chiều dọc nhưng không phổ biến trên nhiều cột.

Dưới đây là cách tôi muốn hạng mục cần hiển thị:

Tôi thực sự muốn tránh phải viết mã theo dõi kích thước kiểm soát để tạo/xoá các cột tùy thuộc vào kích thước của nó.

Trả lời

9

Nếu bạn đặt Orientation thành Vertical, bạn cũng nên đặt chiều cao hiển thị. Ví dụ: WrapPanel, Height="150".

+0

Tôi muốn chiều cao của WrapPanel phải năng động để có những không gian dọc nó cần phải hiển thị các mục trong 2 cột (hoặc 3, hoặc 4, vv .. tùy thuộc vào chiều rộng của điều khiển) – danbord

+0

@danbord, nó không hoạt động như thế. 'WrapPanel' sẽ đặt tất cả các mục phù hợp trong cột đầu tiên theo chiều dọc và tất cả các mục còn lại được lan truyền sang cột tiếp theo. Trong trường hợp của bạn, 'WrapPanel' sẽ đặt tất cả các mục trong một cột vì có giới hạn về chiều cao. – Zabavsky

1

Cách duy nhất để thực hiện việc này với WrapPanel là đặt rõ ràng Height.

Dường như bạn muốn các mục được trải đều ra trên các cột có cột bên trái có nhiều nhất một mục so với cột ở bên phải. Nếu đó là những gì bạn đang tìm kiếm thì bạn sẽ cần phải tạo bảng tùy chỉnh của riêng bạn. Hãy xem this để xem cách bắt đầu. Bạn sẽ cần một thuộc tính phụ thuộc ItemWidth và ItemHeight và tính toán có bao nhiêu cột bạn có thể có bằng cách sử dụng ItemWidth và chiều rộng có sẵn.

2

Đó là loại hành vi là không thể với một WrapPanel mà không xác định của nó Height

Một thay thế bạn có thể sử dụng là một Grid, nơi ở OnLoadedOnSizeChanged, nó tính toán có bao nhiêu cột sẽ phù hợp, sau đó đặt Row/Định nghĩa cột của lưới và Grid.Row/Grid.Column của từng đối tượng trong mã phía sau. Nó không đẹp, nhưng nó khá đơn giản để đặt lại với nhau và sẽ hoạt động.

Tùy chọn khác sẽ tạo Bảng tùy chỉnh của riêng bạn sắp xếp các mục theo cách bạn muốn. Bạn thậm chí có thể tìm thấy thứ gì đó có sẵn trực tuyến đã thực hiện điều đó

3

Cuối cùng, có một thứ hoạt động nhưng cần mã. Tôi đồng ý với tất cả các bạn khi bạn nói rằng chúng ta cần phải thay đổi kích thước chiều cao của WrapPanel để làm cho nó hoạt động.Đây là giải pháp của tôi:

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

đây là 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

Tôi vừa mới làm quen với 'ScrollViewer.ViewportHeight' gần đây ... có lẽ phần dưới cùng của [câu trả lời này] (http://stackoverflow.com/a/11157916/302677) có thể giúp bạn? – Rachel

+0

+1: Điều này làm việc tuyệt vời cho tôi với một số chỉnh sửa rất nhỏ. Cảm ơn các giải pháp! :) – reSPAWNed

+2

Chỉ cần một FYI: Nếu bạn đang sử dụng một ItemsControl thay vì một WrapPanel và bạn tự động thay đổi ItemsSource, sau đó nó sẽ không làm theo cho đến khi bạn thay đổi kích thước cửa sổ. Tôi đã nhận nó làm việc bằng cách sử dụng sự kiện LayoutUpdated hơn là sự kiện SizeChanged, mà sẽ được gọi là thường xuyên hơn, nhưng như bạn có thể đọc trên MSDN được ưa thích khi rối tung với bố trí. – reSPAWNed

Các vấn đề liên quan