Как предотвратить этот цикл макета? - PullRequest
1 голос
/ 27 марта 2012

enter image description here

На рисунке показаны эти небольшие пробелы.Большие синие контейнеры между пробелами являются держателями содержимого, ширина которых определяется.Красная граница - это изменяемый размер держателя .

Таким образом, два внешних пробела описывают левый и правый отступ красного держателя .Два пробела рядом с каждым контейнером - это левый и правый поля каждого контейнера .

Каждый раз, когда я изменяю размер держателя SizeChangedсобытие этого становится.

gapsize = (holderWidth - summedUpWidthsOfAllContainers) / numberOfGaps

Я получаю holderWidth через свойство ActualWidth (UIElement).Я перепривязываю (Silverlight hack) MarginProperty каждого контейнера и PaddingProperty держателя каждый раз, когда возникает событие SizeChanged (UpdateTarget не работает в Silverlight и INotifyPropertyChanged не доступно).Это делается с помощью метода UpdateMargins(), который вызывается в обработчике событий SizeChanged.

Я пытаюсь предотвратить невидимое обновление полей (менее одного пикселя), сравнивая предыдущие и новые поля.

Но при таком подходе я время от времени вызываю циклы компоновки.Теперь я просто хотел спросить, есть ли логическая ошибка.Я прочитал этот блог и попытался решить его таким образом.Но эти циклы макета все еще появляются.

Я делаю это для центрирования держателей контента ( контейнеров ) каждый раз, когда размер держателя изменяется.Я знаю, что решетка с двумя столбцами также была бы жизнеспособным решением.Но проблема в том, что красный держатель должен быть WrapPanel, что в этом случае второй синий контейнер переходит под первый, если держатель становится слишкоммаленький, чтобы показать их рядом друг с другом.

Ответы [ 2 ]

3 голосов
/ 27 марта 2012

По моему мнению, изменение чего-либо в визуальном дереве в событии SizeChanged может в конечном итоге привести к проблемам с производительностью из-за нескольких циклов компоновки, которые вызываются, если вы не будете осторожны (это похоже на проблему, которую вы описываете).

Если вам нужно расположить содержимое определенным образом, я бы посоветовал создать новую панель и переопределить методы ArrangeOverride и MeasureOverride, которые используются во время цикла размещения.Вы можете использовать существующий исходный код WrapPanel (загружаемый из CodePlex в Ms-Pl) и изменить логику для размещения содержимого по своему усмотрению.

В Интернете есть множество статей о создании пользовательских панелей и цикле макета Silverlight.

Извините, я не могу помочь с вашей проблемой напрямую, но, надеюсь, эта информация может быть вам полезна

1 голос
/ 27 марта 2012

Нетрудно создать панель, которая будет просто делать то, что вы хотите.Вот пример, который дает равное количество пространства каждому дочернему элементу:

using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace GapPanel
{
    public class GapPanel : Panel
    {
        protected override Size MeasureOverride(Size availableSize)
        {
            if (Children.Count == 0)
                return base.MeasureOverride(availableSize);
            // allot equal space to each child; you may want different logic 
            var spacePerChild = new Size(availableSize.Width / Children.Count,
                                         availableSize.Height);
            foreach (var child in Children)
                child.Measure(spacePerChild);
            var totalWidth = Children.Sum(child => child.DesiredSize.Width);
            var maxHeight = Children.Max(child => child.DesiredSize.Height);
            return new Size(totalWidth, maxHeight);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (Children.Count == 0)
                return base.ArrangeOverride(finalSize);
            var gap = (finalSize.Width - Children.Sum(
                       child => child.DesiredSize.Width)) / (Children.Count + 1);
            var spacePerChild = (finalSize.Width - gap * (Children.Count + 1))
                                / Children.Count;
            for (int i = 0; i < Children.Count; i++)
            {
                var child = Children[i];
                child.Arrange(new Rect(i * spacePerChild + (i + 1) * gap, 0,
                                       spacePerChild, finalSize.Height));
            }
            return finalSize;
        }
    }
}

Вы бы использовали его так же, как обычную панель:

<my:GapPanel>
    <Button HorizontalAlignment="Center" Width="200" Height="200">abc!</Button>
    <Button HorizontalAlignment="Center" Width="200" Height="200">foo!</Button>
    <Button HorizontalAlignment="Center" Width="100" Height="200">bar!</Button>
</my:GapPanel>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...