簡體   English   中英

如何從WPF中的項目容器中獲取項目?

[英]How to get item from item container in WPF?

我目前正在嘗試在樹視圖中進行拖放操作(使用數據綁定和 HierarchicalDataTemplate),並讓拖放工作,但我在嘗試讓拖放工作時遇到了問題,因為我需要得到正在拖放的數據項並將其添加到其子節點的項目集合中。

//treeitem is the name of my item data class

private void TreeViewItem_Drop(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("DragableTreeViewItem"))
        {
     //the data of the treeitem i need to duplicate, provided by the drag operation
            TreeItem data = e.Data.GetData("DragableTreeViewItem") as TreeItem;
            TreeViewItem tvi = sender as TreeViewItem;
            //here im getting the treeviewitem, but i need the treeitem
        }
    }

關於如何解決這個問題,我最好的想法是在樹的初始化/加載時將 treeitem 分配為 treeviewitem 的標簽,為此我需要獲取該項目的 itemcontainer,我已經有了一個工作功能獲取我在啟動 DoDrag() 時使用的內容

//returns the item container of the parent of the TreeItem given
private TreeViewItem GetParentContainerFromItem(TreeItem ti)
    {
        List<TreeItem> GetOrderedParents(TreeItem item)
        {
            TreeItem currentParent = item;
            List<TreeItem> items = new List<TreeItem>();

            int i = 0;
            do
            {
                if (currentParent.parentItem != null)
                {
                    items.Insert(0, currentParent);
                    currentParent = currentParent.parentItem;
                }
                else
                {
                    items.Insert(0, currentParent);
                    i++;
                    return items;
                }
            } while (i == 0);
            return null;
        }

        //the local tree in a list, ordered from the original item (in this case "ti") at 0, down to the root at the end of the list
        List<TreeItem> LocalHierarchy = GetOrderedParents(ti);
        if (LocalHierarchy != null)
        {
         //print out the names of each treeitem in it, in order from the root down
            string hierarchyString = "";
            foreach (TreeItem t in LocalHierarchy)
            {
                if (hierarchyString == "")
                {
                    hierarchyString = t.Title;
                }
                else
                {
                    hierarchyString = (hierarchyString + ", " + t.Title);
                }
            }
            System.Console.WriteLine(hierarchyString);

            TreeViewItem localCurrentParent = null;
            TreeViewItem finalContainer = null;

            //walk down the tree in order to get the container of the parent 
            foreach (TreeItem t in LocalHierarchy)
            {

                //if the parent of the item given is a root node, meaning we can return its container
                if (LocalHierarchy.IndexOf(t) == 0 && (LocalHierarchy.IndexOf(t) == (LocalHierarchy.Count - 2)))
                {
                    finalContainer = treeView.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
                    break;
                }
                else
                //if we're at a root node
                if (LocalHierarchy.IndexOf(t) == 0)
                {
                    localCurrentParent = treeView.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
                }
                else
                //if we're at the 2nd to last, AKA the parent of the item given
                if (LocalHierarchy.IndexOf(t) == (LocalHierarchy.Count - 2))
                {
                    finalContainer = localCurrentParent.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
                    break;
                }
                else
                {
                    localCurrentParent = localCurrentParent.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
                }
            }

            if (finalContainer == null)
            {
                System.Console.WriteLine("Final container is null");
            }
            return finalContainer;
        }
        else
        {
            System.Console.WriteLine("ERROR: LocalHierarchy is null");
            return null;
        }
    }

這在用於啟動 DoDrag() 時似乎很完美

private void DoDrag()
    {
        if(selectedItem != null)
        {
            TreeItem t = selectedItem;
            TreeViewItem tvi = null;
            if (t.parentItem == null)
            {
                //it has no parent, and is a root node
                tvi = treeView.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
            }
            else
            {
                //it has a parent, and i can get the container for the parent
                tvi = GetParentContainerFromItem(t).ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
            }
            DragDrop.DoDragDrop(tvi, new DataObject("DragableTreeViewItem", t, true), DragDropEffects.Copy);
            dragNeeded = false;
        }
        else if(selectedItem == null)
        {
            Console.WriteLine("Selected item was null; cant drag");
        }
    }

但是當我嘗試在我的函數中使用它來分配容器標簽時,它說 Container 為 null 並且 GetParentContainerFromItem 返回 null,但我的函數沒有記錄它返回 null

private void AssignContainerTag(TreeItem t)
    {
        TreeViewItem Container = null;

        if (t.parentItem == null)
        {
            //its a root node
            Container =  treeView.ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
            Container.Tag = t;
        }
        else
        {
            //it is not a root node
             Container = GetParentContainerFromItem(t).ItemContainerGenerator.ContainerFromItem(t) as TreeViewItem;
            Container.Tag = t;
        }
    }

我花了幾天的時間苦苦思索為什么這似乎不起作用,所以如果有人能給我一些關於我做錯了什么的指示,或者我可以從容器中取出物品的其他方式,那將是一個救星。 如果寫的不好,還請見諒,我已經筋疲力盡了,准備睡覺了。

你的問題有點令人困惑。 但看起來您正在嘗試獲取作為拖放操作的放置目標的TreeViewItem的數據項。

這很簡單。 您需要知道的是,如果項容器是通過數據綁定 ( ItemsControl.ItemsSource ) 自動生成的,則容器的DataContext就是數據項本身。
這適用於ItemsControl所有項目容器(例如, ComboBoxItemListBoxItemListViewItem )。

所以TreeViewItem.DataContext引用由TreeViewItem包裝的底層TreeItem實例:

private void TreeViewItem_Drop(object sender, DragEventArgs e)
{
  if (e.Data.GetDataPresent("DragableTreeViewItem"))
  {
    var sourceItem = e.Data.GetData("DragableTreeViewItem") as TreeItem;

    var dropTargetItemContainer = sender as TreeViewItem;
    var dropTargetItem = targetItemContainer.DataContext as TreeItem;
  }
}

評論

看起來您使用ItemContainerGenerator錯誤的。 TreeView.ItemContainerGenerator將只處理頂級項目(即子項目)。 但是由於樹節點可以有子節點,每個TreeViewItem本身就是一個ItemsControl因為它包含一個ItemsPresenter來顯示子項。
因此,您必須使用適當的ItemContainerGenerator來檢索子容器,否則ItemContainerGenerator將返回null

對於頂級項目,請使用TreeView.ItemContainerGenerator
對於子項,使用父項的TreeViewItem.ItemContainerGenerator

此外,在啟用 UI 虛擬化的情況下,並非所有容器都會在加載TreeView時生成。 它們在需要時生成,例如用於顯示。 這些容器( TreeViewItem )也被共享以節省資源。 因此,一旦您設置了TreeViewItem.Tag屬性,它的值可能會丟失,因為稍后會生成一個新的TreeViewItem實例來包裝數據項。

因此,您從根節點開始並獲取其生成的容器。 現在通過使用特定算法遍歷TreeViewItems來執行樹搜索,直到找到DataContext等於您正在查找的數據項的節點,例如,修改Tag屬性。
您可以通過引用treeViewItemA.Items屬性訪問例如treeViewItemA的子項,並通過為每個子項調用treeVieItemA.ItemContainerGenerator.ContainerFromItem方法來獲取它們的容器:

例子

public static class MyExtensions
{
  // Get item container of item from TreeView, TreeViewItem, ListView or any ItemsControl
  public static bool TryGetContainerOfChildItem<TItemContainer>(this ItemsControl itemsControl, object item, out TItemContainer itemContainer) where TItemContainer : DependencyObject
  {
    itemContainer = null;
    foreach (object childItem in itemsControl.Items)
    {
      if (childItem == item)
      {
        itemContainer = (TItemContainer) itemsControl.ItemContainerGenerator.ContainerFromItem(item);
        return true;
      }

      DependencyObject childItemContainer = itemsControl.ItemContainerGenerator.ContainerFromItem(childItem);
      if (childItemContainer is ItemsControl childItemsControl && childItemsControl.TryGetContainerOfChildItem(item, out itemContainer))
      {
        return true;
      }
    }

    return false;
  }
}

用法

// Search whole TreeView
if (treeView.TryGetContainerOfChildItem(item, out TreeViewItem itemContainer)
{
  ...
}

// Search from a specific parent TreeViewItem node
if (treeViewItem.TryGetContainerOfChildItem(item, out TreeViewItem itemContainer)
{
  ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM