How to get TreeViewItem from HierarchicalDataTemplate item?

前端 未结 11 1435
失恋的感觉
失恋的感觉 2020-12-02 11:34

I have a TreeView which uses a HierarchicalDataTemplate to bind its data.

It looks like this:



        
11条回答
  •  盖世英雄少女心
    2020-12-02 12:12

    Inspired by Fëanor’s answer, I’ve attempted to make the TreeViewItem easily accessible for every data item that a TreeViewItem has been created for.

    The idea is to add a TreeViewItem-typed field to the view model, also exposed via an interface, and have the TreeView automatically populate it whenever the TreeViewItem container is created.

    This is done by subclassing TreeView and attaching an event to the ItemContainerGenerator, which records the TreeViewItem whenever it’s created. Gotchas include the fact that TreeViewItems are created lazily, so there might genuinely not be one available at certain times.

    Since posting this answer, I've developed this further and used it for a long time in one project. No issues so far, other than the fact that this violates MVVM (but also saves you a ton of boilerplate for the simple cases). Source here.

    Usage

    Select the parent of the selected item and collapse it, ensuring that it’s in the view:

    ...
    var selected = myTreeView.SelectedItem as MyItem;
    selected.Parent.TreeViewItem.IsSelected = true;
    selected.Parent.TreeViewItem.IsExpanded = false;
    selected.Parent.TreeViewItem.BringIntoView();
    ...
    

    Declarations:

    
        ...
        
            
                
            
        
        ...
    
    
    class MyItem : IHasTreeViewItem
    {
        public string Name { get; set; }
        public ObservableCollection Children { get; set; }
        public MyItem Parent;
        public TreeViewItem TreeViewItem { get; set; }
        ...
    }
    

    Code

    public class TreeViewWithItem : TreeView
    {
        public TreeViewWithItem()
        {
            ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
        }
    
        private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
        {
            var generator = sender as ItemContainerGenerator;
            if (generator.Status == GeneratorStatus.ContainersGenerated)
            {
                int i = 0;
                while (true)
                {
                    var container = generator.ContainerFromIndex(i);
                    if (container == null)
                        break;
    
                    var tvi = container as TreeViewItem;
                    if (tvi != null)
                        tvi.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
    
                    var item = generator.ItemFromContainer(container) as IHasTreeViewItem;
                    if (item != null)
                        item.TreeViewItem = tvi;
    
                    i++;
                }
            }
        }
    }
    
    interface IHasTreeViewItem
    {
        TreeViewItem TreeViewItem { get; set; }
    }
    

提交回复
热议问题