Data binding to SelectedItem in a WPF Treeview

后端 未结 20 1190
南方客
南方客 2020-11-22 05:39

How can I retrieve the item that is selected in a WPF-treeview? I want to do this in XAML, because I want to bind it.

You might think that it is SelectedItem

20条回答
  •  猫巷女王i
    2020-11-22 06:29

    I suggest an addition to the behavior provided by Steve Greatrex. His behavior doesn't reflects changes from the source because it may not be a collection of TreeViewItems. So it is a matter of finding the TreeViewItem in the tree which datacontext is the selectedValue from the source. The TreeView has a protected property called "ItemsHost", which holds the TreeViewItem collection. We can get it through reflection and walk the tree searching for the selected item.

    private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var behavior = sender as BindableSelectedItemBehaviour;
    
            if (behavior == null) return;
    
            var tree = behavior.AssociatedObject;
    
            if (tree == null) return;
    
            if (e.NewValue == null) 
                foreach (var item in tree.Items.OfType())
                    item.SetValue(TreeViewItem.IsSelectedProperty, false);
    
            var treeViewItem = e.NewValue as TreeViewItem; 
            if (treeViewItem != null)
            {
                treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
            }
            else
            {
                var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    
                if (itemsHostProperty == null) return;
    
                var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel;
    
                if (itemsHost == null) return;
    
                foreach (var item in itemsHost.Children.OfType())
                    if (WalkTreeViewItem(item, e.NewValue)) break;
            }
        }
    
        public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue) {
            if (treeViewItem.DataContext == selectedValue)
            {
                treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
                treeViewItem.Focus();
                return true;
            }
    
            foreach (var item in treeViewItem.Items.OfType())
                if (WalkTreeViewItem(item, selectedValue)) return true;
    
            return false;
        }
    

    This way the behavior works for two-way bindings. Alternatively, it is possible to move the ItemsHost acquisition to the Behavior's OnAttached method, saving the overhead of using reflection every time the binding updates.

提交回复
热议问题