I knew how to implement 2 levels of TreeView by defining HierarchicalDataTemplate.DataType to 2 concreate class. I also found some topics about defining HierarchicalDataTemplate.DataType to interface such as: WPF HiercharchicalDataTemplate.DataType: How to react on interfaces? Any way to use interfaces with wpf HierarchicalDataTemplate
But I have two levels in TreeView: folders and files, it is contracted by two interfaces: IFolder and IFile. When I create a nested TreeViewItems, TargetInvocationException is thrown. But it is OK if just create only one level of TreeViewItem.
This is code: (Can download whole VS2010 solution here (rename extension name from png to zip after downloaded): http://img.bbs.csdn.net/upload/201307/23/1374565982_74852.png )
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:ItemTemplateSelector x:Key="ItemTemplateSelector">
<local:ItemTemplateSelector.FolderTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:IFolder}" ItemsSource="{Binding Items}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</local:ItemTemplateSelector.FolderTemplate>
<local:ItemTemplateSelector.FileTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:IFile}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</local:ItemTemplateSelector.FileTemplate>
</local:ItemTemplateSelector>
</Window.Resources>
<Grid>
<TreeView Name="tvwFiles" ItemTemplateSelector="{DynamicResource ItemTemplateSelector}" />
</Grid>
class ItemTemplateSelector : DataTemplateSelector
{
public DataTemplate FolderTemplate { get; set; }
public DataTemplate FileTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
IFolder folder = item as IFolder;
if (folder != null)
{
return FolderTemplate;
}
IFile file = item as IFile;
if (file != null)
{
return FileTemplate;
}
return null;
}
}
public interface IFolder
{
string Name { get; set; }
}
public interface IFile
{
string Name { get; set; }
}
public class Folder : IFolder
{
public string Name { get; set; }
public ICollection<object> Items
{
get
{
ICollection<object> items = new List<object>();
if (SubFolders != null)
{
foreach (var folder in SubFolders)
items.Add(folder);
}
if (Files != null)
{
foreach (var file in Files)
items.Add(file);
}
return items;
}
}
public ICollection<IFolder> SubFolders { get; set; }
public ICollection<IFile> Files { get; set; }
public Folder(string name)
{
Name = name;
}
}
public class File : IFile
{
public string Name { get; set; }
public File(string name)
{
Name = name;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<object> dirs = new ObservableCollection<object>();
Folder folder = new Folder("Root");
dirs.Add(folder);
for (int i = 0; i < 3; ++i)
{
Folder subfolder = new Folder("Folder" + i);
for (int j = 0; j < 3; ++j)
{
File File = new File("File" + j);
subfolder.Files.Add(File);
}
folder.SubFolders.Add(subfolder);
}
tvwFiles.ItemsSource = dirs;
}
}