I've build a function which generates a treeview in winforms. It includes subfolders and files with recursion. Now i want to translate this over to wpf.
I'm having trouble figuring out how to handle the classes. I know i have to make my own custom class 'treenode' which would have a property 'parent' similar to the winforms treenode.
However in wpf I need two different types of treenodes so i can properly bind the wpf by data type. I have a working example in wpf using familys, I'm just not sure how to get my winform version translated to wpf. Can someone help me get my winform version working in wpf?
Then end goal is getting my treeview in WPF to populate using a directories and files as seen in my winforms example. However the styling of the WPF version should maintain the 'icons' displaying for files and folders.
i hope someone can help me get this working properly. Any suggestions and comments are welcome.
ViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Linq;
namespace WpfApplication1
{
public class ViewModel : ObservableObject
{
// Properties
private ObservableCollection<DirectoryNode> directoryNodes;
public ObservableCollection<DirectoryNode> DirectoryNodes
{
get { return directoryNodes; }
set
{
directoryNodes = value;
NotifyPropertyChanged("DirectoryNodes");
}
}
private ObservableCollection<string> formats;
public ObservableCollection<string> Formats
{
get { return formats; }
set
{
formats = value;
NotifyPropertyChanged("Formats");
}
}
private ObservableCollection<string> directories;
public ObservableCollection<string> Directories
{
get { return directories; }
set
{
directories = value;
NotifyPropertyChanged("Directories");
}
}
// Creating data for testings
public ViewModel()
{
Formats = new ObservableCollection<string>();
Directories = new ObservableCollection<string>();
DirectoryNodes = new ObservableCollection<DirectoryNode>();
// create some dummy test data, eventually will be push to GUI
Formats.Add(".txt");
Formats.Add(".png");
Directories.Add(System.Environment.GetEnvironmentVariable("USERPROFILE"));
PopulateTree(Directories);
}
// Functions
static bool IsValidFileFormat(string filename, ObservableCollection<string> formats)
{
if (formats.Count == 0) return true;
string ext = Path.GetExtension(filename);
bool results = formats.Any(fileType => fileType.Equals(ext, StringComparison.OrdinalIgnoreCase));
return results;
}
public static DirectoryNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
DirectoryNode directoryNode = new DirectoryNode(){Filename=directoryInfo.Name};
foreach (var directory in directoryInfo.GetDirectories())
{
try
{
directoryNode.Children.Add(CreateDirectoryNode(directory));
}
catch (UnauthorizedAccessException) { }
}
foreach (var file in directoryInfo.GetFiles())
{
if (IsValidFileFormat(file.FullName, Formats))
{
FileNode node = new FileNode() { Filename = file.FullName };
directoryNode.Children.Add(node);
}
}
return directoryNode;
}
public void PopulateTree(ObservableCollection<string> directories)
{
foreach (string directoryPath in directories)
{
if (Directory.Exists(directoryPath))
{
DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);
DirectoryNodes.Add(CreateDirectoryNode(directoryInfo));
}
}
}
}
public class FileNode
{
public string Filepath { get; set; }
public string Filename { get; set; }
public DirectoryNode Parent { get; set; }
}
public class DirectoryNode
{
public string Filepath { get; set; }
public string Filename { get; set; }
public DirectoryNode Parent { get; set; }
public ObservableCollection<FileNode> Children { get; set; }
}
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
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:self="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="300"
WindowStartupLocation="CenterScreen">
<Window.DataContext>
<self:ViewModel/>
</Window.DataContext>
<Grid Margin="5">
<TreeView ItemsSource="{Binding Directories}" Grid.Row="1" Grid.ColumnSpan="2">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:DirectoryNode}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center" FontFamily="WingDings" Content="1"/>
<TextBlock Text="{Binding Filename}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type self:FileNode}">
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center" FontFamily="WingDings" Content="2"/>
<TextBlock Text="{Binding Filename}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
Working Winforms Example
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Linq;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public static List<string> formats = new List<string>();
public Form1()
{
InitializeComponent();
//add userfolder
List<string> Directories = new List<string>();
Directories.Add(System.Environment.GetEnvironmentVariable("USERPROFILE"));
// get formats accepted
formats.Add(".txt");
formats.Add(".png");
PopulateTree(Directories, formats);
}
static bool IsValidFileFormat(string filename, List<string> formats)
{
if (formats.Count == 0) return true;
string ext = Path.GetExtension(filename);
bool results = formats.Any(fileType => fileType.Equals(ext, StringComparison.OrdinalIgnoreCase));
return results;
}
public static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
TreeNode directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
{
try
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
catch (UnauthorizedAccessException) { }
}
foreach (var file in directoryInfo.GetFiles())
{
if (IsValidFileFormat(file.FullName, formats))
{
TreeNode node = new TreeNode(file.FullName);
node.ForeColor = Color.Red;
directoryNode.Nodes.Add(node);
}
}
return directoryNode;
}
public void PopulateTree(List<string> directories, List<string> formats)
{
// main collection of nodes which are used to populate treeview
List<TreeNode> treeNodes = new List<TreeNode>();
foreach (string directoryPath in directories)
{
if (Directory.Exists(directoryPath))
{
DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);
treeNodes.Add(CreateDirectoryNode(directoryInfo));
}
}
treeView1.Nodes.AddRange(treeNodes.ToArray());
}
}
}
would these classes work alright
- yes. Only that DirectoryItem should have anObservableCollection<FileItem>
in order to show the files inside a directory in the TreeView, if you want. – Federico Berasategui