2012-11-02 92 views
2

我試圖讓用戶圍繞TreeView移動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; 
} 
..... 

我確實花了至少一個小時研究這個話題,我明白TreeViewItem必須從它的邏輯父被分離了,我從測試父知道根本TreeViewItem總是一個TreeView,我只是不知道如何分離它。我知道你會盡力讓這個網站擺脫無聊的問題,我希望我的網站不是一個。任何洞察力將不勝感激。

回答

0

的輸入以及感謝,但是,經過進一步的調試,我才意識到我的問題是內getContainingList遞歸調用,

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

應該

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

這就是我得到的2編碼是

3

簡單的回答是

[whatevertheparentofyourUIElement].Children.Remove(childrenitem); 

正確的答案是:不要操縱代碼UI元素。你有一個概念上的(設計)缺陷:你的UI不是數據,你的數據是數據,你的UI只是在屏幕上顯示你的數據的好方法。如果您的ViewModel級別中只有一個ObservableCollection<T>,並且不得不操縱它,那會不會更容易?相反,你正在操縱複雜的WPF對象,做了很多不必要的意大利麪代碼,並且由於UI虛擬化和類似的東西,你最終會遇到很多問題。

如果您已經實施的TreeView以正確的方式,這個任務將減少到2行代碼:從ObservableCollection刪除選定的項目,而在另一個ObservableCollection位於其他地方的層次結構ViewModel其插入。

+0

whoa whoa whoa ...不必要的,但意大利麪?我只是喜歡自己做事。你能否詳細說明「快速」答案?每個TreeViewItem的父項都是一個TreeView,但TreeView沒有任何子項字段。不過,我會考慮使用ObserableCollection,謝謝 – user1067042