Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
242 views
in Technique[技术] by (71.8m points)

treeview - WPF: Select TreeViewItem broken past the root level

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 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}">

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. :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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 =(

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;
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...