代码之家  ›  专栏  ›  技术社区  ›  imekon

在wpf treeview中删除将跳转到父级

  •  0
  • imekon  · 技术社区  · 16 年前

    我尝试了这里讨论的解决方案: WPF treeview itemselected moves incorrectly when deleting an item

    但是,在删除项目时,我仍然看到选择跳转到父级。我做错什么了?

    主窗口

    <Window x:Class="TreeViewDelete.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Tree View Delete sample" Height="350" Width="525">
    
    <Window.Resources>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsSelected" Value="{Binding Selected, Mode=TwoWay}"/>
            <EventSetter Event="KeyDown" Handler="OnTreeKeyDown"/>
        </Style>
        <HierarchicalDataTemplate x:Key="recursiveTemplate" ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView Name="m_tree" ItemsSource="{Binding Children}" ItemTemplate="{StaticResource recursiveTemplate}"/>
    </Grid>
    </Window>
    

    主窗口.xaml.cs

    public partial class MainWindow : Window
    {
        private Container m_root, m_child;
    
        public MainWindow()
        {
            InitializeComponent();
    
            m_root = new Container("Root");
    
            m_child = new Container("main");
    
            m_child.Add(new Container("k1"));
            m_child.Add(new Container("k2"));
            m_child.Add(new Container("k3"));
            m_child.Add(new Container("k4"));
            m_child.Add(new Container("k5"));
    
            m_root.Add(m_child);
    
            m_tree.DataContext = m_root;
        }
    
        private IEnumerable<T> GetVisualAncestorsOfType<T>(DependencyObject obj) where T : DependencyObject
        {
            for (; obj != null; obj = VisualTreeHelper.GetParent(obj))
                if (obj is T)
                    yield return (T)obj;
        }
    
        private void OnTreeKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Delete:
                    {
                        TreeViewItem item = sender as TreeViewItem;
    
                        if (item != null)
                        {
                            Container container = item.Header as Container;
    
                            if (container != null)
                            {
                                Container parent = container.Parent;
    
                                // Find the currently focused element in the TreeView's focus scope
                                DependencyObject focused =
                                  FocusManager.GetFocusedElement(
                                    FocusManager.GetFocusScope(m_tree)) as DependencyObject;
    
                                // Scan up the VisualTree to find the TreeViewItem for the parent
                                var parentContainer = (
                                  from element in GetVisualAncestorsOfType<FrameworkElement>(focused)
                                  where (element is TreeViewItem && element.DataContext == parent)
                                        || element is TreeView
                                  select element
                                  ).FirstOrDefault();
    
                                parent.Remove(container);
    
                                if (parentContainer != null)
                                {
                                    parent.Children[0].Selected = true;
                                    parentContainer.Focus();
                                }
                            }
                        }
    
                        e.Handled = true;
                    }
                    break;
            }
        }
    }
    

    最后是container.cs

    public class Container : INotifyPropertyChanged
    {
        private bool m_selected;
        private string m_name;
        private ObservableCollection<Container> m_children;
        private Container m_parent;
    
        public Container(string name)
        {
            m_name = name;
            m_children = new ObservableCollection<Container>();
            m_parent = null;
            m_selected = false;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public string Name
        {
            get
            {
                return m_name;
            }
    
            set
            {
                m_name = value;
    
                OnPropertyChanged("Name");
            }
        }
    
        public Container Parent
        {
            get
            {
                return m_parent;
            }
    
            set
            {
                m_parent = value;
            }
        }
    
        public bool Selected
        {
            get
            {
                return m_selected;
            }
    
            set
            {
                m_selected = value;
    
                OnPropertyChanged("Selected");
            }
        }
    
        public ObservableCollection<Container> Children
        {
            get
            {
                return m_children;
            }
        }
    
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    
        public void Add(Container child)
        {
            m_children.Add(child);
    
            child.Parent = this;
        }
    
        public void Remove(Container child)
        {
            m_children.Remove(child);
    
            child.Parent = null;
        }
    }
    
    2 回复  |  直到 11 年前
        1
  •  0
  •   Nima R    16 年前

    我自己没有检查过,但我认为您可以通过使用ObservableCollections的CollectionChanged事件来实现这一点。在这里,可以将事件附加到子集合,以便在删除其中一个子集合时,可以将其选定属性(例如,集合的第一个子集合)设置为true。类似下面的代码:

    附加事件:

        Children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Children_CollectionChanged); 
    

    事件实施:

    void Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
        {
            Children.First().Selected = true;
        }
    }
    
        2
  •  0
  •   BenMorel Manish Pradhan    12 年前

    我尝试了这里提供的解决方案: "TreeView selected item when removing nodes" 在一个简单的应用程序中,它工作得很漂亮。不用在应用程序中说,我正在开发它

    看看这篇文章的内容,我似乎需要一个TreeView项目,它是我的项目的容器。所以我尝试:

    m_tree.ItemContainerGenerator.ContainerFromItem
    

    但这始终返回空值。然后我读了以下内容: TreeView.ItemContainerGenerator.ContainerFromItem returns null 在那一刻,我的大脑几乎烧断了导火索!

    它似乎到达了我想要被选中的树视图项,我必须从我的层次结构的顶部开始,沿着树向下工作,直到我到达我想要的位置。因此,我的容器数据具有父属性,因此我构建了一个对象堆栈:

    Stack<Containerl> stack = new Stack<Container>();
    
    Container toBeSelected = ... my object to be selected after deletion ...
    
    while (toBeSelected != null)
    {
        stack.Push(toBeSelected);
    
        toBeSelected = toBeSelected.Parent;
    }
    

    然后,删除层次结构中的所有项,然后执行以下操作:

    TreeViewItem item = m_tree.ItemContainerGenerator.ContainerFromItem(stack.Pop()) as TreeViewItem;
    
    while(item != null && (stack.Count > 0))
    {
        item = item.ItemContainerGenerator.ContainerFromItem(stack.Pop()) as TreeViewItem;
    }
    
    // Force this item to be selected, and set focus
    item.IsSelected = true;
    item.Focus();
    

    它起作用了!!!!