Reputation: 6458
I'm trying to build a TreeView using MVVM
in a WPF
App but I don't understand how to handle HierarchicalDataTemplate
. My TreeView
should represent a folder structure which contains folders within folders and so on.
My folder ViewModel
is defined as follows:
public class TreeViewFolderViewModel : ViewModelBase
{
private int _id;
private int _parentId;
private string _text;
private string _key;
private ObservableCollection<TreeViewFolderViewModel> _children;
public int Id
{
get { return this._id; }
set { Set(() => Id, ref this._id, value); }
}
public int ParentId
{
get { return this._parentId; }
set { Set(() => ParentId, ref this._parentId, value); }
}
public string Text
{
get { return this._text; }
set { Set(() => Text, ref this._text, value); }
}
public string Key
{
get { return this._key; }
set { Set(() => Key, ref this._key, value); }
}
public ObservableCollection<TreeViewFolderViewModel> Children
{
get { return this._children ?? (this._children =
new ObservableCollection<TreeViewFolderViewModel>()); }
set { Set(() => Children, ref this._children, value); }
}
}
My model has the same structure as my ViewModel
so the final ViewModel
is a list of folders that contain child folders and so forth. I'm using recursion to load all these folders and that part is working fine.
Where I'm stuck is on how to define and load this ViewModel into the actual TreeView.
I've read Hierarchical DataBinding in TreeView using MVVM pattern and while I more or less understand what's going on, but each of the levels of the TreeView
represent a different object type while my TreeView
has only one object type and I'm confused as to how I'm suppose to define this.
The Root ViewModel
property in my MainWindowViewModel is of type TreeViewFolderViewModel
which means I have a single object which represents to root of my TreeView. This object has Children of type TreeViewFolderViewModel
which in turn have also Children of type TreeViewFolderViewModel
and so forth
How do I defined this in XAML
? I have the following defined:
<TreeView Grid.Row="1" Margin="5,0,5,5" ItemsSource="{Binding RootFolder}"/>
And I've got a Hierarchical
template defined as follows:
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Children}"
DataType="{x:Type viewmodels:SharePointFolderTreeViewViewModel}">
<Label Content="{Binding Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
But nothing is loading up.
Any ideas on how I can resolve this?
Thanks.
Upvotes: 0
Views: 67
Reputation: 11211
I prepared a small sample to illustrate.
ViewModels
public class TreeViewFolderViewModel : ViewModelBase
{
private int id;
public int Id
{
get { return id; }
set { id = value; OnPropertyChanged("Id"); }
}
private string text;
public string Text
{
get { return text; }
set { text = value; OnPropertyChanged("Text"); }
}
private ObservableCollection<TreeViewFolderViewModel> children;
public ObservableCollection<TreeViewFolderViewModel> Children
{
get
{
return children ?? (children =
new ObservableCollection<TreeViewFolderViewModel>());
}
set { children = value; OnPropertyChanged("Children"); }
}
}
public class TreeViewModel : ViewModelBase
{
private List<TreeViewFolderViewModel> items;
public List<TreeViewFolderViewModel> Items
{
get { return items; }
set { items = value; OnPropertyChanged("Items"); }
}
public TreeViewModel()
{
Items = new List<TreeViewFolderViewModel>()
{
new TreeViewFolderViewModel()
{
Id =0, Text="RootFolder", Children=new ObservableCollection<TreeViewFolderViewModel>()
{
new TreeViewFolderViewModel() { Id = 10, Text = "FirstFolder", Children=new ObservableCollection<TreeViewFolderViewModel>() { new TreeViewFolderViewModel() { Id = 11, Text = "FirstChild" } } } ,
new TreeViewFolderViewModel() { Id = 20, Text = "SecondFolder", Children = new ObservableCollection<TreeViewFolderViewModel>() { new TreeViewFolderViewModel() { Id = 21, Text = "SecondChild" } } } ,
new TreeViewFolderViewModel() { Id = 30, Text = "ThirdFolder", Children = new ObservableCollection<TreeViewFolderViewModel>() { new TreeViewFolderViewModel() { Id = 31, Text = "ThirdChild" } } }
}
}
};
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
MainWindow.xaml
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:TreeViewModel />
</Window.DataContext>
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Children}"
DataType="{x:Type local:TreeViewFolderViewModel}">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="Id" />
<Binding Path="Text" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Items}" />
</Grid>
</Window>
Upvotes: 1