I try to learn using treeview base one MVVM. I refer this tutorial https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode
It's very helpful and I try to understand it by rewrite code
TreeViewViewModel.cs
public class TreeViewViewModel
{
private ObservableCollection<TreeNode> _firstNode;
public static TreeNode _seletectedNode;
private ObservableCollection<TreeNode> _node;
private ICommand _addCommand;
public TreeViewViewModel(TreeNode rootNode) : this(rootNode, null) {}
public TreeViewViewModel(TreeNode rootNode, TreeViewViewModel parentNode)
{
_firstNode = new ObservableCollection<TreeNode>(rootNode.Node);
_node = new ObservableCollection<TreeNode>((from child in rootNode.Node select child).ToList<TreeNode>());
_addCommand = new AddCommand(this);
}
public ObservableCollection<TreeNode> FirstNode
{
get { return _firstNode; }
set { _firstNode = value; }
}
public ObservableCollection<TreeNode> Node
{
get { return _node; }
set { _node = value; }
}
public TreeNode Selected
{
get{ return _seletectedNode; }
set{ _seletectedNode = value;}
}
public ICommand AddCommand
{
get { return _addCommand; }
}
}
TreeNode.cs
public class TreeNode : INotifyPropertyChanged
{
private ObservableCollection<TreeNode> _Node = new ObservableCollection<TreeNode>();
private string _Name;
private string _ID;
private bool _isExpanded;
private bool _isSelected;
public ObservableCollection<TreeNode> Node
{
get { return _Node; }
set
{
_Node = value;
OnPropertyChanged("Node");
}
}
public string Name
{
get { return _Name; }
set { _Name = value; OnPropertyChanged("Name"); }
}
public string ID
{
get { return _ID; }
set { _ID = value; OnPropertyChanged("ID");}
}
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (value != _isExpanded)
{
_isExpanded = value;
this.OnPropertyChanged("IsExpanded");
}
}
}
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
this.OnPropertyChanged("IsSelected");
if (_isSelected) {TreeViewViewModel._seletectedNode = this;}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
AddCommand.cs
public class AddCommand : ICommand
{
private TreeViewViewModel _TreeView;
public AddCommand(TreeViewViewModel treeView)
{
_TreeView = treeView;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
//Show Selected item
//MessageBox.Show(_TreeView.Selected.Name);
//Add first level item
//_TreeView.FirstNode.Add(new TreeNode { Name = "Hihi" });
//Rename selected item
//_TreeView.Selected.Name = "Hello";
//Remove first level item
//_TreeView.FirstNode.Remove(_TreeView.Selected);
//Add selected item
//_TreeView.Selected.Node.Add(new TreeNode { Name = "Hihi" });
}
}
MainWindown.xaml.cs
public partial class MainWindow : Window
{
public TreeViewViewModel _TreeView;
public MainWindow()
{
InitializeComponent();
TreeNode rootNode = new TreeNode
{
Name = "David",
Node =
{
new TreeNode
{
Name = "Alberto",
Node =
{
new TreeNode
{
Name = "Zena",
Node =
{
new TreeNode
{
Name = "Nick",
}
}
},
new TreeNode
{
Name = "Sarah",
},
}
},
new TreeNode
{
Name = "Komrade",
}
}
};
_TreeView = new TreeViewViewModel(rootNode);
base.DataContext = _TreeView;
}
}
MainWindow.xaml
<Window x:Class="TreeviewMVVM_Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TreeviewMVVM_Test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Margin="10,35,380,260"/>
<Button Margin="154,27,324,268" Command="{Binding AddCommand}" />
<TreeView x:Name="treeView"
ItemsSource="{Binding FirstNode}"
BorderThickness="0"
Height="Auto" Width="Auto"
Margin="21,84,349,19">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Node}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
My source code is working fine, I can add childnode from selected node, remove first level node, rename selected node, get selected node. But only 1 thing, I don't know how to store and get parent's node
I read thought out the Josh tutorial, it's seem to be parent node is stored in contructor. Here below is Josh's code. If i use like that Parent node is a TreeViewViewModel, not a node. I don't want like that, Is there any way to make parent node to TreeNode type. I want to use like this _treeView.Seletect.Parent.Name and it's should print parent name of selected node.
private PersonViewModel(Person person, PersonViewModel parent)
{
_person = person;
_parent = parent;
_children = new ObservableCollection<PersonViewModel>(
(from child in _person.Children
select new PersonViewModel(child, this))
.ToList<PersonViewModel>());
}
I don't want like that
care to explain why don't you like it? in MVVM if you feel the need to access parent item, then you know you're doing something wrong. You can access the parent VM by adding a parent property, there shouldn't be any reason to access the parent View. you can implement something that finds the parent view and then read its data context but that breaks MVVM. – Bizhan