HierarchicalDataTemplate TreeView - ContainerFromItem只返回第一个I
本文关键字:返回 第一个 ContainerFromItem TreeView HierarchicalDataTemplate | 更新日期: 2023-09-27 18:06:43
我有一个如下的TreeView:
<TreeView
Loaded="tv_Loaded_1"
DockPanel.Dock="Bottom"
Name="tv"
ItemsSource="{Binding XPath=*}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate
ItemsSource="{Binding XPath=*}">
<StackPanel
Orientation="Horizontal">
<TextBlock
Text="{Binding Name}"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
在代码后面,我使用以下xml作为DataContext:
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"<a><b><c></c><d></d></b><e><f></f><g></g></e></a>");
DataContext = doc;
TreeView正在生成良好,但在枚举项目时,我得到TreeViewItem仅用于第一个XmlNode(根节点即<a>
)和剩余的XmlNodes在层次结构中没有任何相应的TreeViewItem存在。
private IEnumerable<TreeViewItem> Enumerate(ItemCollection items)
{
foreach (XmlElement element in items)
{
TreeViewItem item = tv.ItemContainerGenerator.ContainerFromItem(element) as TreeViewItem;
if (item != null) //When second call with <a>.Items, item is null
{
yield return item;
}
//Enumerate is called again with <a>.Items
//Exception in second call, because item is null
foreach (TreeViewItem i in Enumerate(item.Items))
{
yield return i;
}
}
}
private void tv_Loaded_1(object sender, RoutedEventArgs e)
{
var list = Enumerate(tv.Items).ToList();
}
为什么在树的XmlNodes的其余部分没有任何TreeViewItem存在?
这是因为其他项目不在tv中,它们在'a' TreeViewItem中。但是,他们真的还没有在'a',因为TreeViewItem没有展开,布局还没有更新。
你可以通过传入ItemsControl (tv或父TreeViewItem)并使用它来获取ContainerFromItem来使其工作。但是,在你得到一个容器之前,你必须展开项目并更新它的布局。
下面是完成上述任务的一些代码。副作用是树被完全展开。private IEnumerable<TreeViewItem> Enumerate(ItemsControl itemsControl, ItemCollection items)
{
foreach (XmlElement element in items)
{
TreeViewItem item = itemsControl.ItemContainerGenerator.ContainerFromItem(element) as TreeViewItem;
if (item != null) //When second call with <a>.Items, item is null
{
item.IsExpanded = true;
item.UpdateLayout();
yield return item;
}
//Enumerate is called again with <a>.Items
//Exception in second call, because item is null
foreach (TreeViewItem i in Enumerate(item, item.Items))
{
yield return i;
}
}
}
private void tv_Loaded_1(object sender, RoutedEventArgs e)
{
var list = Enumerate(tv, tv.Items).ToList();
}
实际上,你只需要传入ItemsControl。此外,我还加入了一些代码来关闭树。
private IEnumerable<TreeViewItem> Enumerate(ItemsControl itemsControl)
{
foreach (XmlElement element in itemsControl.Items)
{
TreeViewItem item = itemsControl.ItemContainerGenerator.ContainerFromItem(element) as TreeViewItem;
if (item != null) //When second call with <a>.Items, item is null
{
item.IsExpanded = true;
item.UpdateLayout();
yield return item;
}
//Enumerate is called again with <a>.Items
//Exception in second call, because item is null
foreach (TreeViewItem i in Enumerate(item))
{
yield return i;
}
}
}
private void tv_Loaded_1(object sender, RoutedEventArgs e)
{
var list = Enumerate(tv).ToList();
// Unexpand all the items
list.ForEach(tvi => tvi.IsExpanded = false);
}