2

ユーザーが移動できるようにしようとしてTreeViewItemsいますTreeView(具体的には、コントロールを押しながら矢印キーを押すことによって)。ノードを他のノードに移動したり、他のノードから移動したり、トップ レベルでノードを上下に移動したりできますが、サブノード内でノードを上に移動しようとしても何も起こりません。次の例外が発生します。

要素にはすでに論理的な親があります。新しい親にアタッチする前に、古い親からデタッチする必要があります。

これは、ノードを元のコレクションに追加しようとしたときに発生します (もちろん削除した後)。元の実装は次のとおりです。

private TreeViewItem getParent(TreeViewItem item)
{
    for (int i=0; i<fragment_tree.Items.Count; ++i)
    {
        TreeViewItem r = getParent((TreeViewItem)(fragment_tree.Items[i]), item);
        if (r != null)
        {
            return r;
        }
    }
    return null;
}
private TreeViewItem getParent(TreeViewItem test, TreeViewItem item)
{
    for (int i=0; i<test.Items.Count; ++i)
    {
        if (test.Items[i] == item)
        {
            return test;
        }
    }
    for (int i=0; i<test.Items.Count; ++i)
    {
        TreeViewItem r = getParent((TreeViewItem)(test.Items[i]), item);
        if (r != null)
        {
            return r;
        }
    }
    return null;
}
private ItemCollection getContainingList(TreeViewItem item, out int id)
{
    return getContainingList(fragment_tree.Items, item, out id);
}
private ItemCollection getContainingList(ItemCollection test, TreeViewItem item, out int id)
{
    for (int i=0; i<test.Count; ++i)
    {
        if (test[i] == item)
        {
            id = i;
            return test;
        }
    }
    for (int i=0; i<test.Count; ++i)
    {
        ItemCollection r = getContainingList((TreeViewItem)(test[i]), out id);
        if (r != null)
        {
            return r;
        }
    }
    id = -1;
    return null;
}
private void fragment_tree_PreviewKeyDown(object sender, KeyEventArgs e)
{
    TreeViewItem selected_item = (TreeViewItem)(fragment_tree.SelectedItem);
    if (selected_item.Header is String)
    {
        if (e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) || e.KeyboardDevice.IsKeyDown(Key.RightCtrl))
        {
            if (e.Key == Key.Up)
            {
                int id;
                ItemCollection collection = getContainingList(selected_item, out id);
                if (collection != null) // it'll never be null, but w/e
                {
                    if (id > 0)
                    {
                        collection.RemoveAt(id);
                        collection.Insert(id-1, selected_item);
                        selected_item.IsSelected = true;
                    }
                }
                e.Handled = true;
            }
            else if (e.Key == Key.Down)
            {
                int id;
                ItemCollection collection = getContainingList(selected_item, out id);
                if (collection != null) // it'll never be null, but w/e
                {
                    if (id < collection.Count)
                    {
                        collection.RemoveAt(id);
                        collection.Insert(id+1, selected_item); // here is the exception
                        selected_item.IsSelected = true;
                    }
                }
                e.Handled = true;
            }
            else if (e.Key == Key.Left)
            {
                TreeViewItem parent = getParent(selected_item);
                if (parent != null)
                {
                    int id;
                    ItemCollection collection = getContainingList(parent, out id);
                    parent.Items.RemoveAt(id);
                    collection.Insert(id, selected_item);
                    selected_item.IsSelected = true;
                }
                e.Handled = true;
            }
            else if (e.Key == Key.Right)
            {
                int id;
                ItemCollection collection = getContainingList(selected_item, out id);
                if (id+1 < collection.Count)
                {
                    TreeViewItem next_item = (TreeViewItem)(collection[id+1]);
                    collection.RemoveAt(id);
                    next_item.Items.Insert(0, selected_item);
                    next_item.IsExpanded = true;
                    selected_item.IsSelected = true;
                }
                e.Handled = true;
            }
        }
    }

選択したものの深いクローンを作成しようとしましたがTreeViewItem(オーバーヘッドが発生したくないのですが)、奇妙な動作が発生しました。サブツリー内で項目を上下に移動しようとすると、親に飛び出します。最上位のノードを上下に移動しようとすると、隣接するノードが削除されます。根本的な何かが欠けているように感じる

private TreeViewItem cloneTreeViewItem(TreeViewItem item)
{
    TreeViewItem r = new TreeViewItem();
    r.Header = item.Header;
    r.Tag = item.Tag;
    for (int i=0; i<item.Items.Count; ++i)
    {
        r.Items.Add(cloneTreeViewItem((TreeViewItem)(item.Items[i])));
    }
    return r;
}

....
if (e.Key == Key.Up)
{
    int id;
    ItemCollection collection = getContainingList(selected_item, out id);
    if (collection != null) // it'll never be null, but w/e
    {
        if (id > 0)
        {
            collection.RemoveAt(id);
            TreeViewItem clone = cloneTreeViewItem(selected_item);
            collection.Insert(id-1, clone);
            clone.IsSelected = true;
        }
    }
    e.Handled = true;
}
else if (e.Key == Key.Down)
{
    int id;
    ItemCollection collection = getContainingList(selected_item, out id);
    if (collection != null) // it'll never be null, but w/e
    {
        if (id < collection.Count)
        {
            collection.RemoveAt(id);
            TreeViewItem clone = cloneTreeViewItem(selected_item);
            collection.Insert(id+1, clone);
            clone.IsSelected = true;
        }
    }
    e.Handled = true;
}
.....

私はこのトピックを調査するのに少なくとも 1 時間費やしTreeViewItemましTreeViewItemTreeView。あなたがこのサイトにくだらない質問をしないように努めていることは知っていますが、私の質問がそうでないことを願っています。任意の洞察をいただければ幸いです。

4

2 に答える 2

3

クイックな答えは

[whatevertheparentofyourUIElement].Children.Remove(childrenitem);

正しい答えは、コードで UIElements を操作しないことです。UI はデータではなく、データはデータであり、UI はデータを画面に表示するための優れた方法です。レベルのObservableCollection<T>どこかにがあり、それを操作する必要がある場合は、はるかに簡単ではないでしょうか? ViewModel代わりに、複雑な WPF オブジェクトを操作し、多くの不要なスパゲッティ コードを実行し、UI 仮想化などによって多くの問題が発生することになります。

正しい方法で実装した場合TreeView、このタスクは 2 行のコードに削減されます。選択した項目を から削除し、階層構造の別の場所にあるObservableCollection別の項目に挿入します。ObservableCollectionViewModel

于 2012-11-03T03:24:12.563 に答える
0

ご意見ありがとうございます。しかし、さらにデバッグした後、問題が getContainingList 内の再帰呼び出しであることに気付きました。

ItemCollection r = getContainingList((TreeViewItem)(test[i]), out id);

する必要があります

ItemCollection r = getContainingList(((TreeViewItem)(test[i])).Items, item, out id);

それは私が午前2時にコーディングすることで得られるものです

于 2012-11-04T17:49:58.730 に答える