如何防止这种布局循环?

时间:2012-03-27 14:47:36

标签: c# .net silverlight xaml layout

enter image description here

图片显示了这些小差距。间隙之间的大的蓝色容器是内容持有者,其宽度是确定的。红色边框是可调整大小的持有者

因此,两个外部间隙描述了红色持有者的左右填充。每个容器旁边的两个间隙是每个容器的左右边距

每当我调整持有者的大小时,它的SizeChanged事件都会被提升。

gapsize = (holderWidth - summedUpWidthsOfAllContainers) / numberOfGaps

我通过ActualWidth(UIElement)属性获取holderWidth。每次SizeChanged事件被提升时,我都会重新绑定(Silverlight hack)每个容器的MarginProperty和持有者的PaddingProperty(UpdateTarget不做'在Silverlight中工作,INotifyPropertyChanged不可用)。这是在UpdateMargins()方法中完成的,该方法在SizeChanged事件处理程序中调用。

我尝试通过比较之前的新边距来防止边距(小于一个像素)的不可见刷新。

但是使用这种方法我会不时地引起布局周期。现在我只是想问一下是否存在逻辑错误。我读过this博客并试图以这种方式解决它。但这些布局周期仍然存在。

每次持有人调整大小时,我这样做都是为了使内容持有者(容器)居中。我知道具有两列的网格也是可行的解决方案。但问题是红色持有者必须是WrapPanel,在这种情况下,第二个蓝色容器会跳到第一个持有者太小而无法将它们彼此相邻显示。

2 个答案:

答案 0 :(得分:3)

在我看来,在SizeChanged事件中更改可视树上的任何内容都可能最终导致性能问题,因为如果您不小心会调用多个布局周期(这似乎与您描述的问题一致)。

如果您需要以特定方式布局内容,我建议您创建一个新面板并覆盖布局周期中使用的ArrangeOverride和MeasureOverride方法。您可以使用现有的WrapPanel源代码(可从Ms-Pl下的CodePlex下载)并根据需要更改逻辑以布局内容。

网上有很多关于创建自定义面板和Silverlight布局周期的文章。

抱歉,我无法直接解决您的问题,但希望这些信息对您有用

答案 1 :(得分:1)

创建一个能够完全按照自己的意愿行事的面板并不难。这是一个给每个孩子提供相等空间的例子:

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>