WPF:选择超出根级别的 TreeViewItem [英] WPF: Select TreeViewItem broken past the root level
问题描述
我正在尝试按 ID 选择一个 TreeViewItem,但在使其超过第一个(根)级别时遇到问题.我已经对此进行了大量阅读,并且正在使用以下方法.
I'm trying to select a TreeViewItem by ID, but having problems getting it to work past the first (root) level. I've done so much reading round on this and am using the method below.
private static bool SetSelected(ItemsControl parent, INestable itemToSelect) {
if(parent == null || itemToSelect == null) {
return false;
}
foreach(INestable item in parent.Items) {
if(item.ID == itemToSelect.ID) { // just comparing instances failed
TreeViewItem container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if(container != null) {
container.IsSelected = true;
container.Focus();
return true;
}
}
ItemsControl childControl = parent.ItemContainerGenerator.ContainerFromItem(item) as ItemsControl;
if(SetSelected(childControl, itemToSelect))
return true;
}
return false;
}
INestable 是基础级接口,由 IGroup 和 IAccount 实现:
INestable is the base level interface, implemented by IGroup and IAccount:
public interface INestable {
string ID { get; set; }
...
}
public interface IAccount : INestable {
...
}
public interface IGroup : INestable {
public IList<INestable> Children
...
}
我认为它一定与数据模板有关(也许):
I think it must have something to do with the datatemplates (perhaps):
<HierarchicalDataTemplate DataType="{x:Type loc:IGroup}" ItemsSource="{Binding Children}" x:Key="TreeViewGroupTemplate">
<HierarchicalDataTemplate DataType="{x:Type loc:IAccount}" x:Key="TreeViewAccountTemplate">
The Template selector for the treeview returns thr group template for IGroups and the account template for IAccounts:
<conv:TreeTemplateSelector x:Key="TreeTemplateSelector" AccountTemplate="{StaticResource TreeViewAccountTemplate}" GroupTemplate="{StaticResource TreeViewGroupTemplate}"/>
<TreeView ItemTemplateSelector="{StaticResource TreeTemplateSelector}">
它适用于所有顶级项目,只有低于此级别的项目,并且调试确认 parent.ItemContainerGenerator 确实包含所有级别的项目.
It works for all top level items, just nothing below that, and debugging confirms parent.ItemContainerGenerator does contain the items for all levels.
我知道有很多代码,但我正在花费数小时试图让它工作.谢谢你的帮助.:)
I know there's a lot of code but I'm burning through hours trying to get this to work. Thanks for any help. :)
推荐答案
问题是嵌套的 ItemContainerGenerators
并不是一开始就生成的,而是按需生成的.更重要的是,它们是在单独的线程中生成的,因此您必须在生成器上监听 StatusChanged
以确保它已准备就绪 =(
The problem is that the nested ItemContainerGenerators
aren't generated all at the beginning, they are generated on-demand. And even more so, they are generated in a separate thread, so you have to listen to a StatusChanged
on the generator to be sure it is ready =(
有些人建议使用 Dispatcher
(就像在这个 Bea 的帖子).我尝试实现 Dispatcher 解决方案,但由于某种原因它不起作用......生成器仍然是空的 =(
Some people suggest to play with the Dispatcher
(like in this Bea's post). I tried to implement the Dispatcher solution, but it didn't work for some reason... the generators are still empty =(
所以我结束了另一个,你特别要求树更新它的布局,这会导致扩展节点的生成.这是最后一种方法……您可能想对其进行一些测试以验证它是否适合您的需求.它可能会折叠一些在运行之前展开的节点.
So I ended up with another one, where you specifically ask the tree to update its layout, which causes the generation for the expanded nodes. Here's the final method... you might want to test it a little to verify that it suites your needs. It might collapse some nodes that were expanded before its run.
private static bool SetSelected(TreeView treeView, ItemsControl parentControl, INestable itemToSelect)
{
if (parentControl == null || itemToSelect == null)
{
return false;
}
foreach (INestable item in parentControl.Items)
{
TreeViewItem container = parentControl.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (item.ID == itemToSelect.ID)
{ // just comparing instances failed
container.IsSelected = true;
container.Focus();
return true;
}
container.IsExpanded = true;
treeView.UpdateLayout();
WaitForPriority(DispatcherPriority.Background);
if (SetSelected(treeView, container, itemToSelect))
return true;
else
container.IsExpanded = false;
}
return false;
}
这篇关于WPF:选择超出根级别的 TreeViewItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!