WPF无法使ItemContainerGenerator.ContainerFromItem工作。
WPF无法使ItemContainerGenerator.ContainerFromItem工作。
我在这里,这里以及其他很多地方进行了查找,但我似乎无法在WPF TreeView上使用ItemContainerGenerator.ContainerFromItem
方法!我尝试传入实际要查看的项,但没有任何进展,所以我尝试获取TreeView中的第一项。这是我的示例代码:
private static bool ExpandAndSelectItem(ItemsControl parentContainer, object itemToSelect) { // 这并不起作用。 parentContainer.BringIntoView(); // 可能是虚拟化的,调整布局并重试。 parentContainer.UpdateLayout(); parentContainer.ApplyTemplate(); TreeViewItem topItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(parentContainer.Items[0]); // 除非展开一次父节点,否则无法找到子容器 if ((topItem != null) && !topItem.IsExpanded) { topItem.IsExpanded = true; parentContainer.UpdateLayout(); } }
正如你看到的,我尝试调用了许多“更新”方法,试图使TreeView“可见”和“可访问”。困境似乎是,除非展开第一个TreeViewItem,否则无法使用ContainerFromItem()
,但在ContainerFromItem()
可行之前,我无法获取TreeViewItem来展开它!
另一个有趣的事情发生在这里:当我打开这个窗口(它是一个UserControl)时,ContainerFromItem()
返回null,但是如果我关闭窗口再打开它,ContainerFromItem()
开始返回非null。我应该寻找或强制触发的任何事件吗?
问题原因:无法通过ItemContainerGenerator.ContainerFromItem获取到TreeViewItem,可能是因为在调用该方法时,TreeViewItem还未加载完成。
解决方法:将逻辑代码放在TreeView的Loaded事件处理程序中,确保在TreeView加载完成后再调用ItemContainerGenerator.ContainerFromItem方法。
文章内容如下:
在WPF中,有一个问题是无法通过ItemContainerGenerator.ContainerFromItem方法获取到TreeViewItem。经过一番探索,我发现了解决这个问题的方法。
首先,我在XAML中为TreeView添加了一个"Loaded"事件的事件处理程序,并在该事件处理程序中调用了我的逻辑代码。
...
然后,在代码中实现了该事件处理程序:
private void MyTreeView_Load(object sender, RoutedEventArgs e) { ShowSelectedThing(MyTreeView, ThingToFind); } private static bool ShowSelectedThing(ItemsControl parentContainer, object ThingToFind) { // 检查当前层级的树 foreach (object item in parentContainer.Items) { TreeViewItem currentContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item); if ((currentContainer != null) && (item == ThingToFind)) { currentContainer.IsSelected = true; currentContainer.BringIntoView(); return true; } } // 如果在当前层级找不到,检查下一层级的子项 foreach (object item in parentContainer.Items) { TreeViewItem currentContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item); if ((currentContainer != null) && (currentContainer.Items.Count > 0)) { // 必须展开currentContainer才能查看其子项 currentContainer.IsExpanded = true; currentContainer.UpdateLayout(); if (!ShowSelectedThing(currentContainer, ThingToFind)) { // 如果在子项中还未找到目标项,则将currentContainer折叠起来 currentContainer.IsExpanded = false; } else { // 找到了目标项 return true; } } } // 默认情况 return false; }
希望这对某些人有所帮助。在现实世界中,由于客户的需求苛刻、奇怪的要求以及紧迫的截止日期,有时候我们不得不采取一些“hack”的方式来解决问题。
我很感谢这个被称为“HACK”的解决方法。不明白为什么这个方法会被评为-1。我知道它没有实现ViewModel/ModelView,但并不是所有的事情都需要通过ViewModel来完成。随着时间的推移,人们可能会对WPF的绑定方式更加熟悉。公司并不总是愿意花费额外的时间和金钱来创建所有现有的额外东西,只是为了让事情变得更容易。有时候并没有长期的考虑。在我看来,这就是为什么对象上仍然有事件处理程序的原因,因为不是所有的东西都可以被绑定起来。
非常感谢这个解决方法!它对我帮助很大!
WPF无法使ItemContainerGenerator.ContainerFromItem正常工作的原因是当容器生成器的状态为'NotStarted'或'ContainersGenerating'时,无法找到容器。为了解决这个问题,可以使用上面提供的方法来找到数据项的容器。该方法首先检查容器生成器的状态,如果状态不是'ContainersGenerated',则创建一个TaskCompletionSource对象,并注册一个事件处理程序。在事件处理程序中,如果生成器的状态为'ContainersGenerated',则移除事件处理程序并设置TaskCompletionSource的结果为null;如果生成器的状态为'Error',则移除事件处理程序并设置TaskCompletionSource的异常为InvalidOperationException。然后,将事件处理程序添加到生成器的状态更改事件中,并根据情况展开TreeViewItem和更新布局。最后,通过生成器的ContainerFromItem方法来获取数据项的容器。如果容器为空,可以通过遍历itemsControl的父项来递归查找数据项的容器。如果找到了容器,则返回容器,否则返回null。
通过使用上述方法,可以解决WPF无法使用ItemContainerGenerator.ContainerFromItem的问题。
WPF中的ItemContainerGenerator.ContainerFromItem无法工作的原因是在调用Lv.ItemContainerGenerator.ContainerFromItem(Lv.SelectedItem)时,容器对象Dep没有正确地获取到。这可能是因为ItemContainerGenerator在ListView中尚未正确地初始化。
解决方法是在调用ContainerFromItem之前,先调用Lv.UpdateLayout()来确保ItemContainerGenerator已经正确初始化。在调用UpdateLayout()方法后,再通过ContainerFromItem方法获取到容器对象Dep,并将其转换为ListViewItem类型,最后调用其Focus方法进行焦点设置。
这个问题可能也会在TreeView及其项中出现,解决方法也是类似的。