![](/img/trans.png)
[英]WPF Is there a way to get the container for an item on a selectionchanged event?
[英]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
所有項目容器(例如, ComboBoxItem
、 ListBoxItem
、 ListViewItem
)。
所以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.