WP7自定义MultiColumnStackPanel子项已有父项

时间:2012-06-13 09:31:27

标签: c# silverlight windows-phone-7 mobile

我正在使用this网站上的示例来创建MultiColumnStackPanel。

但是有一个问题。加载页面后,stackpanel看起来很好,就像示例一样。但是当我导航到下一页然后返回上一页时,我得到一个例外:

InvalidOperationException
使用以下消息:
Element is already the child of another element.

所以我认为原始自定义堆栈面板中包含的项目正被添加到新的自定义堆栈面板中。但是为什么 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 };
    }
}

xaml示例:

<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>

1 个答案:

答案 0 :(得分:0)

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

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

当导航到下一页然后导航回来时,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>()));