1

このサイトの例を使用して MultiColumnStackPanel を作成しています。

ただし、1 つ問題があります。ページがロードされると、スタックパネルは問題なく、例とまったく同じように見えます。しかし、次のページに移動してから前のページに戻ると、例外が発生します。

無効な操作例外
次のメッセージが表示されます。
要素はすでに別の要素の子です。

.

オリジナルのカスタムスタックパネルに含まれていたアイテムが、新しいカスタムスタックパネルに追加されていると思います。しかし、なぜ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>
4

1 に答える 1

0

私はそれを理解し、私の発見を共有したいと思いました。

MultiColumnStackPanel のコンストラクターで、関数はStackPanel のイベントにLoadItems()バインドされます。Loaded

次のページに移動してから戻ると、先ほど考えたように MultiColumnStackPanel が再度作成されません。LoadedMultiColumnStackPanelのイベントは、単純に再度発生します。

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);
    }
}

時々、ちょっとした内省が必要です =)

編集

もう1つ注意してください。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 に答える