1

我正在使用站点中的示例来创建 MultiColumnStackPanel。

然而有一个问题。加载页面后,堆栈面板看起来很好,与示例完全相同。但是当我导航到下一页然后返回上一页时,我得到了一个例外:

无效操作异常
带有以下消息:
元素已经是另一个元素的子元素。

.

所以我认为原始自定义堆栈面板中包含的项目正在添加到新的自定义堆栈面板中。但是,为什么MultiColumnStackPanel被“刷新”并且MultiColumnStackPanel.Items仍然存在?

还有其他人对此问题有解释/解决方案吗?

提前致谢

.

MultiColumnStackPanel 类:

public class MultiColumnStackPanel : StackPanel
{
    public int NumberOfColumns { get; set; }

    public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items",
            typeof(Collection<UIElement>),
            typeof(MultiColumnStackPanel),
            new PropertyMetadata(new Collection<UIElement>()));

    public Collection<UIElement> Items
    {
        get { return (Collection<UIElement>)GetValue(ItemsProperty); }
    }

    public MultiColumnStackPanel()
    {
        Loaded += (s, e) =>
        {
            LoadItems();
        };
    }

    void LoadItems()
    {
        Children.Clear();

        if (Items != null)
        {
            StackPanel sp = CreateNewStackPanel();
            foreach (UIElement item in Items)
            {
                sp.Children.Add(item);
                if (sp.Children.Count == NumberOfColumns)
                {
                    Children.Add(sp);
                    sp = CreateNewStackPanel();
                }
            }

            if (sp.Children.Count > 0)
                Children.Add(sp);
        }
    }

    private StackPanel CreateNewStackPanel()
    {
        Orientation oppositeOrientation;

        if(this.Orientation.Equals(Orientation.Vertical))
            oppositeOrientation = Orientation.Horizontal;
        else
            oppositeOrientation = Orientation.Vertical;

        return new StackPanel() { Orientation = oppositeOrientation };
    }
}

xml 示例:

<model:MultiColumnStackPanel x:Name="customStackPanel" Orientation="Horizontal" NumberOfColumns="2">
    <model:MultiColumnStackPanel.Items>
        <Rectangle Height="80" Width="80" Margin="10" Fill="Green" />
        <Rectangle Height="80" Width="80" Margin="10" Fill="Green" />
        <Rectangle Height="80" Width="80" Margin="10" Fill="Green" />
        <Rectangle Height="80" Width="80" Margin="10" Fill="Green" />
    </model:MultiColumnStackPanel.Items>
</model:MultiColumnStackPanel>
4

1 回答 1

0

我想通了,并认为我会分享我的发现。

在 MultiColumnStackPanel 的构造函数中,函数LoadItems()绑定到LoadedStackPanel 的事件。

当导航到下一页然后导航回来时,MultiColumnStackPanel 并没有像我之前想的那样被再次创建。MultiColumnStackPanel的Loaded事件只是再次触发。

public MultiColumnStackPanel()
{
    Loaded += (s, e) =>
    {
        LoadItems();
    };
}

然后我看到每次LoadItems()调用该函数时都会清除该对象的子对象。删除它就可以了,如果孩子们已经在场,则无需Items再次从列表中添加它们。

void LoadItems()
{
    // Children.Clear();

    if (Items != null && (Children == null || Children.Count == 0))
    {
        StackPanel sp = CreateNewStackPanel();
        foreach (UIElement item in Items)
        {
            sp.Children.Add(item);
            if (sp.Children.Count == NumberOfColumns)
            {
                Children.Add(sp);
                sp = CreateNewStackPanel();
            }
        }
        if (sp.Children.Count > 0)
            Children.Add(sp);
    }
}

有时你只需要一点自我反省 =)

编辑

再注意一点,ItemsProperty不应该是静态的

public static readonly DependencyProperty ItemsProperty = // <-- remove static
    DependencyProperty.Register("Items",
    typeof(Collection<UIElement>),
    typeof(MultiColumnStackPanel),
    new PropertyMetadata(new Collection<UIElement>()));
于 2012-06-13T10:41:40.950 回答