Удаление в WPF TreeView переходит к родителю - PullRequest
0 голосов
/ 02 июня 2010

Я попробовал решение, обсуждаемое здесь: Выбранный элемент дерева WPF неправильно перемещается при удалении элемента

Тем не менее, я все еще вижу переход выбора к этому родителю при удалении элемента. Что я делаю не так?

MainWindow.xaml

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

MainWindow.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 ]

0 голосов
/ 11 июня 2010

Я попробовал решение, предоставленное здесь: "TreeView выбранный элемент при удалении узлов" , и в простом приложении оно прекрасно работает. Излишне говорить, что в приложении я работаю над ним не ...

Глядя на то, о чем говорится в статье, мне кажется, мне нужен TreeViewItem, который является контейнером моего элемента. Итак, я попробовал:

m_tree.ItemContainerGenerator.ContainerFromItem

За исключением того, что всегда возвращает ноль. Затем я прочитал следующее: TreeView.ItemContainerGenerator.ContainerFromItem возвращает ноль , и в этот момент мой мозг чуть не перегорел предохранитель!

Кажется, что я получаю доступ к TreeViewItem, который я хочу выбрать, я должен начать с вершины своей иерархии и работать вниз по дереву, пока не доберусь до того места, где я хочу. Итак, мои данные контейнера имеют свойство Parent, поэтому я создал стек объектов:

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();

Работает !!!

0 голосов
/ 02 июня 2010

Я не проверял это сам, но я думаю, что вы можете сделать это, используя событие CollectionChanged ObservableCollections. здесь вы можете прикрепить событие к вашей дочерней коллекции, чтобы при удалении одного из них вы устанавливали для свойства Selected, например, первого дочернего элемента коллекции, значение 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...