Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > WPF и Silverlight > Привязка TreeView к дереву


Автор: zhiday 30.11.2011, 13:12
Добрый день, вопрос в следующем:

Допустим имеется класс:

Код

public class Node
    {
        public string Text { get; set; }

        public Image Icon { get; set; }

        public NodeCollection Children { get; set; }
    }


Где то в коде из этих узлов создаётся что то вроде дерева:

 
Код

public Node GetRootNode()
        {
            NodeCollection nc1 = new NodeCollection();
            nc1.Add(new Node { Text = "Test1" });
            nc1.Add(new Node { Text = "Test2" });
            nc1.Add(new Node { Text = "Test3" });

            NodeCollection nc2 = new NodeCollection();
            nc2.Add(new Node { Text = "Test1" });
            nc2.Add(new Node { Text = "Test2" });
            nc2.Add(new Node { Text = "Test3" });

            NodeCollection nc3 = new NodeCollection();
            nc3.Add(new Node { Text = "Test1" });
            nc3.Add(new Node { Text = "Test2" });
            nc3.Add(new Node { Text = "Test3" });

            var child1 = new Node { Text = "Child1", Children = nc1 };
            var child2 = new Node { Text = "Child2", Children = nc2 };
            var child3 = new Node { Text = "Child3", Children = nc3 };

            NodeCollection nc0 = new NodeCollection();
            nc0.Add(child1);
            nc0.Add(child2);
            nc0.Add(child3);

            return new Node { Text = "Root", Children = nc0};
        }


И вот как мне сделать привязку в XAMLе, к этому Root узлу, что бы мне в TreeView построилось дерево?
Заранее спасибо.

Автор: Gvozdin 30.11.2011, 13:35
http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx

Автор: GRemlin87 21.12.2011, 06:30
хотел бы немного развить тему,  допустим имеем класс описанный выше.но это только model из него делаем viewModel
Код

 public class NodeViewModel : BaseViewModel
    {
        private bool _isSelected;
        public bool IsSelected
        {
            get{ return _isSelected;}
            set{_isSelected = value; OnPropertyChanged(() => IsSelected);}
        }
        public NodeViewModel()
        {
            _childNodes = new ObservableCollection<NodeViewModel>();
            _isSelected = false;
        }
        private Node _node;
        public Node Node
        {
            get{return _node;}
            set{_node = value;}
        }
      
        private ObservableCollection<NodeViewModel> _childNodes;

        public ObservableCollection<NodeViewModel> ChildNodes
        {
            get{ return _childNodes;}
            set{_childNodes = value;}
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

для привязки к treeview использую такой класс
Код

 public class MainWindowViewModel : BaseViewModel
    {
        private NodeViewModel _currentNode;
        public NodeViewModel CurrentNode
        {
            get{return _currentNode;}
            set{ _currentNode = value;}
        }
        private ObservableCollection<NodeViewModel> _parentNodes;
        public ObservableCollection<NodeViewModel> ParentNodes
        {
            get{ return _parentNodes; }
            set{  _parentNodes = value; }
        }
        public MainWindowViewModel()
        {
            _parentNodes = new ObservableCollection<NodeViewModel>();
            NodeViewModel model1 = new NodeViewModel { Node = new Node("Первый нод") };
            NodeViewModel model11 = new NodeViewModel { Node = new Node("Поднод Первого нода") };
            model1.ChildNodes.Add(model11);
            NodeViewModel model12 = new NodeViewModel { Node = new Node("Поднод Второго нода") };
            model1.ChildNodes.Add(model12);
            NodeViewModel model13 = new NodeViewModel { Node = new Node("Поднод Третьего нода") };
            model1.ChildNodes.Add(model13);
            _parentNodes.Add(model1);
            NodeViewModel model2 = new NodeViewModel { Node = new Node("Второй нод") };
            _parentNodes.Add(model2);
            NodeViewModel model3 = new NodeViewModel { Node = new Node("Третий нод") };
            _parentNodes.Add(model3);
            CurrentNode = ParentNodes.First();
        }
    }

и наконец XAML
Код

 <TreeView  ItemsSource="{Binding ParentNodes,Mode=TwoWay}"   >
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate  DataType="{x:Type wpf:MainWindowViewModel}" ItemsSource="{Binding Path=ChildNodes,Mode=TwoWay}">
                    <TextBlock Text="{Binding Node.Name}"></TextBlock>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
            <TreeView.Resources>
                <Style TargetType="TreeViewItem" >
                    <Setter Property="IsSelected" Value="{Binding Path=IsSelected,Mode=TwoWay}"/>
                </Style>
            </TreeView.Resources>
        </TreeView>
        <TextBox Text="{Binding CurrentNode.Node.Name,Mode=TwoWay}"></TextBox>

а теперь собственно проблема. Такая привязка на самом деле изменяет свойство IsSelected в обьекте CurentNode, но он сам об этом не узнаёт и поэтому не получается его изменить, в то же время если изменить свойство Name через TextBox то в MainWindowViewModel  CurrentNode метод get срабатывает, а вот если меняем IsSelected то ничего не происходит. Подскажите в чём ошибка

Автор: Gvozdin 21.12.2011, 22:12
1. "Такая привязка на самом деле изменяет свойство IsSelected в обьекте CurentNode, но он сам об этом не узнаёт"
Q. Я так понимаю IsSelected изменяется как и задумывалось, о чем он сам(NodeViewModel) не узнает?

2. "если изменить свойство Name через TextBox то в MainWindowViewModel  CurrentNode метод get срабатывает, а вот если меняем IsSelected то ничего не происходит"
Q. Что не происходит при изменении IsSelected? И что должно происходить?

Давайте поконкретнее.

Автор: GRemlin87 22.12.2011, 04:24
Возможно я конечно не правильно понимаю механизм NotifyPropertyChaged, но как по моему это должно происходить. Мы через TextBox к которму привязано свойство Name обьекта CurrentNode изменяем это самое свойство и создаём событие PropertyChanged("Name") из за этого события все другие обьекты к которому этот CurrentNode привязан в нашем случае это treeView узнают что он изменился и заного запрашивают его, праверял ставил брекпоинт в метод get CurrentNode всё работает как надо, Но почему когда я изменяю свойство isSelected CurrenNode заного не запрашивают.

Автор: Gvozdin 30.12.2011, 23:25
ни кто не гарантирует ни каких определенных реакций на PropertyChanged.

С чего кому-то запрашивать CurrentNode при изменении свойства у какого-то объекта, пусть даже того что в CurrentNode?
Вызовите OnPropertyChanged("CurrentNode") и скорее всего его запросят.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)