Data binding to SelectedItem in a WPF Treeview

后端 未结 20 1075
南方客
南方客 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条回答
  •  谎友^
    谎友^ (楼主)
    2020-11-22 06:13

    My requirement was for PRISM-MVVM based solution where a TreeView was needed and the bound object is of type Collection<> and hence needs HierarchicalDataTemplate. The default BindableSelectedItemBehavior wont be able to identify the child TreeViewItem. To make it to work in this scenario.

    public class BindableSelectedItemBehavior : Behavior
    {
        #region SelectedItem Property
    
        public object SelectedItem
        {
            get { return (object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }
    
        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
    
        private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var behavior = sender as BindableSelectedItemBehavior;
            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;
            }
            var itemsHostProperty = treeViewItem.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            if (itemsHostProperty == null) return false;
            var itemsHost = itemsHostProperty.GetValue(treeViewItem, null) as Panel;
            if (itemsHost == null) return false;
            foreach (var item in itemsHost.Children.OfType())
            {
                if (WalkTreeViewItem(item, selectedValue))
                    break;
            }
            return false;
        }
        #endregion
    
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            if (this.AssociatedObject != null)
            {
                this.AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
            }
        }
    
        private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e)
        {
            this.SelectedItem = e.NewValue;
        }
    }
    
    
    

    This enables to iterate through all the elements irrespective of the level.

    提交回复
    热议问题