Как мы можем установить точку переноса для WrapPanel?

У меня есть ItemsControl, и я хочу, чтобы данные вводились в два столбца. Когда пользователь изменяет размер до ширины меньше, чем ширина второго столбца, элементы второго столбца должны переноситься в первый столбец. Что-то вроде UniformGrid, но с оберткой.

Мне удалось использовать для этого WrapPanel. Но я вынужден манипулировать и жестко кодировать ItemWidth и MaxWidth WrapPanel для достижения двух столбцов и упаковки. Это не очень хорошая практика.

Есть ли способ установить максимальное количество столбцов или, другими словами, позволить нам решить, в какой момент WrapPanel должен начать перенос?

Некоторый просмотр в Интернете показал, что WrapGrid в Windows 8 Metro имеет эту property. У кого-нибудь есть такая реализация в WPF?


person Gordon Geek-O    schedule 19.03.2012    source источник
comment
Я думаю, что именно так должен работать WrapPanel ... рисовать каждый элемент, пока следующий элемент не подходит, а затем переносить его на новую строку. Вы должны использовать ItemWidth и WrapPanel.Width (или MaxWidth), чтобы указать WrapPanel, когда завершать.   -  person Rachel    schedule 19.03.2012


Ответы (1)


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

var itemsPerRow = (int) (totalWidth/ItemWidth);

чтобы указать максимальное количество столбцов.

Вот код:

public enum ItemSize
{
    None,
    Uniform,
    UniformStretchToFit
}

public class UniformWrapPanel : WrapPanel
{
    public static readonly DependencyProperty ItemSizeProperty =
        DependencyProperty.Register(
            "ItemSize", 
            typeof (ItemSize), 
            typeof (UniformWrapPanel), 
            new FrameworkPropertyMetadata(
                default(ItemSize),
                FrameworkPropertyMetadataOptions.AffectsMeasure,
                ItemSizeChanged));

    private static void ItemSizeChanged(
        DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var uniformWrapPanel = sender as UniformWrapPanel;
        if (uniformWrapPanel != null)
        {
            if (uniformWrapPanel.Orientation == Orientation.Horizontal)
            {
                uniformWrapPanel.ItemWidth = double.NaN;
            }
            else
            {
                uniformWrapPanel.ItemHeight = double.NaN;
            }
        }
    }

    public ItemSize ItemSize
    {
        get { return (ItemSize) GetValue(ItemSizeProperty); }
        set { SetValue(ItemSizeProperty, value); }
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        var mode = ItemSize;

        if (Children.Count > 0 && mode != ItemSize.None)
        {
            bool stretchToFit = mode == ItemSize.UniformStretchToFit;

            if (Orientation == Orientation.Horizontal)
            {
                double totalWidth = availableSize.Width;

                ItemWidth = 0.0;
                foreach (UIElement el in Children)
                {
                    el.Measure(availableSize);
                    Size next = el.DesiredSize;
                    if (!(Double.IsInfinity(next.Width) || Double.IsNaN(next.Width)))
                    {
                        ItemWidth = Math.Max(next.Width, ItemWidth);
                    }
                }

                if (stretchToFit)
                {
                    if (!double.IsNaN(ItemWidth) && !double.IsInfinity(ItemWidth) && ItemWidth > 0)
                    {
                        var itemsPerRow = (int) (totalWidth/ItemWidth);
                        if (itemsPerRow > 0)
                        {
                            ItemWidth = totalWidth/itemsPerRow;
                        }
                    }
                }
            }
            else
            {
                double totalHeight = availableSize.Height;

                ItemHeight = 0.0;
                foreach (UIElement el in Children)
                {
                    el.Measure(availableSize);
                    Size next = el.DesiredSize;
                    if (!(Double.IsInfinity(next.Height) || Double.IsNaN(next.Height)))
                    {
                        ItemHeight = Math.Max(next.Height, ItemHeight);
                    }
                }

                if (stretchToFit)
                {
                    if (!double.IsNaN(ItemHeight) && !double.IsInfinity(ItemHeight) && ItemHeight > 0)
                    {
                        var itemsPerColumn = (int) (totalHeight/ItemHeight);
                        if (itemsPerColumn > 0)
                        {
                            ItemHeight = totalHeight/itemsPerColumn;
                        }
                    }
                }
            }
        }

        return base.MeasureOverride(availableSize);
    }
}
person Phil    schedule 19.03.2012
comment
Сладкий! Спасибо, Фил. Мне удалось адаптировать это в соответствии с моими требованиями. Кстати, есть ли проблемы с производительностью при использовании WrapPanel? - person Gordon Geek-O; 20.03.2012
comment
Не могу сказать о производительности. Кажется, нормально работает примерно с 30-40 предметами. Вам нужно будет попробовать. - person Phil; 20.03.2012