【问题标题】:How to prevent this layout cycle?如何防止这种布局循环?
【发布时间】:2012-03-27 14:47:36
【问题描述】:

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

所以两个外部间隙描述了红色holder的左右padding。每个容器旁边的两个间隙是每个容器的左右margins

每次我调整 holder 的大小时,都会引发 SizeChanged 事件。

gapsize = (holderWidth - summedUpWidthsOfAllContainers) / numberOfGaps

我通过 ActualWidth (UIElement) 属性获得 holderWidth。每次引发SizeChanged 事件时,我都会重新绑定(Silverlight hack)每个 container 的 MarginProperty 和 holder 的 PaddingProperty(UpdateTarget 在 Silverlight 中不起作用和INotifyPropertyChanged 不可用)。这是在UpdateMargins() 方法中完成的,该方法在SizeChanged 事件处理程序中被调用。

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

但使用这种方法时,我会不时导致布局循环。现在我只想问有没有逻辑错误。我已阅读 this 博客并尝试以这种方式解决它。但是这些布局循环仍然会出现。

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

【问题讨论】:

  • 对不起,如果我误解了某些内容,但您为什么不直接使用环绕面板控件作为您的“红色支架”?
  • @Dave S:我实际上为此使用了一个环绕面板。但是,它使列相互粘连。这意味着每次调整支架的大小以防止这种粘连时,我都需要计算这些间隙。
  • 我需要添加一件事。红色支架的宽度由应用程序的窗口大小决定。正如我们所知,包裹面板元素只使用它们需要的尽可能多的空间。我拉伸了这个包裹面板,但我无法将水平对齐的元素居中。这是通过这些差距完成的。
  • 从你的问题中我不清楚你到底想做什么。
  • 我的总结是:我需要一个环绕面板,其宽度由应用程序的窗口宽度决定。它的元素是水平定向的。但是,它的元素不应该相互粘连。如果它有两个容器(蓝色),则换行面板应该有两个“GridColumns”。并且蓝色容器必须居中。

标签: c# .net silverlight xaml layout


【解决方案1】:

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

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

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

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

【讨论】:

  • 是的,你是对的。我认识到我对新旧利润的检查使它变得更好。但是仍然存在布局周期。可能你是对的。我要写一个新的面板。谢谢。
【解决方案2】:

创建一个简单地执行您想要的操作的面板并不难。这是一个为每个孩子提供相同数量空间的示例:

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>

【讨论】:

  • 非常感谢这个。这对我真正需要的小组来说是一个很好的帮助和基础。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-28
  • 2012-10-18
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多